分析redux源码

入口:index.ts(目录)重点标红

 

 

复制代码
import createStore from './createStore'
import combineReducers from './combineReducers'
import bindActionCreators from './bindActionCreators'
import applyMiddleware from './applyMiddleware'
import compose from './compose'
import warning from './utils/warning'
import __DO_NOT_USE__ActionTypes from './utils/actionTypes'
// types// store
export {CombinedState, PreloadedState, Dispatch, Unsubscribe,  Observable, Observer, Store, StoreCreator, StoreEnhancer, StoreEnhancerStoreCreator,ExtendState} from './types/store'
// reducers
export {Reducer,ReducerFromReducersMapObject,ReducersMapObject,StateFromReducersMapObject,ActionFromReducer,ActionFromReducersMapObject} from './types/reducers'
// action creators
export { ActionCreator, ActionCreatorsMapObject } from './types/actions'
// middleware
export { MiddlewareAPI, Middleware } from './types/middleware'
// actions
export { Action, AnyAction } from './types/actions'

export {
  createStore,combineReducers,bindActionCreators,applyMiddleware,compose,__DO_NOT_USE__ActionTypes
}
复制代码

 


用法: const store = createStore( rootReducer, applyMiddleware(thunk));  
createStore接收3个参数(reducer,preloadedState?,enhancer); 上面的applyMiddleware(trunk) 即 enhancer,
如果没有传preloadState参数则会这样:
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { 
      enhancer = preloadedState as StoreEnhancer<Ext, StateExt> 
      preloadedState = undefined 
    }
没有enhancer的情况下,createStore会dispatch一个内部定义的action 来 初始化state,然后返回store
复制代码
dispatch({ type: ActionTypes.INIT } as A)

  const store = ({
    dispatch: dispatch as Dispatch<A>,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  } as unknown) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
  return store
复制代码

 

而有enhancer参数传入的情况下, enhancer被调用两次之后,也同样返回了store
 if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
  
//两次调用
return enhancer(createStore)(reducer,preloadedState as PreloadedState<S>) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext}

 redux 设置了锁,来避免出现一些同步执行一些方法会导致的问题,如果一些情况同步执行,会报错,比如说同时更改和写入state的情况。

let isDispatching = false  //加锁
//初始化state
let currentState = preloadedState as S //preloadState是参数
复制代码
//获取state的函数:
 function getState(): S {
if (isDispatching) { throw new Error( 'You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.' ) } return currentState as S }
复制代码

 

let currentListeners: (() => void)[] | null = [] //初始化当前订阅者列表

let nextListeners = currentListeners //新订阅者列表

 

复制代码
 sunscribe方法:接受一个listener作为参数,产生一个新的listener列表,把新的Listener加入新列表里面,返回unsubscribe方法。
(我们会调用dispatch函数来更新state,而每次state更新时,会通知每个listener。)

function subscribe(listener: () => void) { if (typeof listener !== 'function') { throw new Error('Expected the listener to be a function.') }   //锁 if (isDispatching) { throw new Error( 'You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribelistener for more details.' ) } let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener)   
   function ensureCanMutateNextListeners() {
    //判断是否指向同一个对象
      if (nextListeners === currentListeners) {
        nextListeners = currentListeners.slice()
      }
    }
return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
    if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api-reference/store#subscribelistener for more details.'
        )
      }
    
      isSubscribed = false //设置已经退订
     ensureCanMutateNextListeners() //复制到新的订阅者列表
      const index = nextListeners.indexOf(listener) 
      nextListeners.splice(index, 1) //删除该订阅者
      currentListeners = null
    }
  }
复制代码

 

dispatch函数   (参数是action),调用reducer函数 更新state,并且通知所有最新的listener

let currentReducer = reducer //第一个参数reducer 
复制代码
function dispatch(action: A) { 
if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) }   //同步互斥 if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } try { isDispatching = true
    //执行传入参数的reducer,返回新的state
currentState = currentReducer(currentState, action) } finally { isDispatching = false }    //更新Listener列表,通知所有listener const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action }
复制代码

 其他:

replaceReducer //替换reducer

observable // observable版本的实现

 

2,applyMiddleware.ts

//记得createStore的参数enhancer吗?applyMiddleware(thunk)的返回值,一个函数,被执行了2次。
最终它返回了store,并且加了一个dispatch属性在上面(这个dispatch方法是经过包装过的,最里面才是原来的store.dispatch方法)

复制代码
//定义参数部分略

export default function applyMiddleware( ...middlewares: Middleware[] ): StoreEnhancer<any> { return (createStore: StoreCreator) => <S, A extends AnyAction>( reducer: Reducer<S, A>, ...args: any[] //state ) => {
   //初始化store,这里store会有一个dispatch的方法,这个dispatch会被传给middleware,经过一系列包装。
    const store = createStore(reducer, ...args)
  //变量dispatch
let dispatch: Dispatch
= () => { throw new Error( 'Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.' ) } const middlewareAPI: MiddlewareAPI = { getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args)//把变量dispatch也传给了middlewares }
  //执行了一次middlewares,传递参数。 const chain
= middlewares.map(middleware => middleware(middlewareAPI))

  
//调用了compose2次,且最终返回新的dispatch方法,赋值给变量dispatch。   dispatch = compose<typeof dispatch>(...chain)(store.dispatch)   //设定新的store.dispatch 并返回 store return { ...store, dispatch } } }
复制代码
compose.ts
复制代码
//参数定义略
export default function compose(...funcs: Function[]) { if (funcs.length === 0) { // infer the argument type so it is usable in inference down the line return <T>(arg: T) => arg //T是dispatch函数,dispatch = store.dispatch } if (funcs.length === 1) { return funcs[0] //只有一个,直接返回,然后被传入store.dispatch }  //如果多个参数,多个dispatch合一(嵌套)
  return funcs.reduce((a, b) => (...args: any) => a(b(...args))) 
}
复制代码

 so.. middlewares

redux-trunk源码:
复制代码
function createThunkMiddleware(extraArgument) {return 
  //trunk函数
({ dispatch, getState }) =>
    //被传入middlewareAPI之后
    next =>
    //被传入store.dispatch之后,dipatch = action=>{return dispatch(action)}
       action => {
         if (typeof action === 'function') {
            return action(dispatch, getState, extraArgument);
             }
         return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;
复制代码
用法: dispatch(actionCreater(params))
复制代码
export function actionCreater(params){
//返回的dispatch函数
return (dispatch,getState)=>{ sendAsyncRequest(params).then((response)=>{ let action ={ type:'WHAT_EVER', payload:response }; return dispatch(action); }) } }


复制代码

 

 3.combineReducer.ts

 

用法:  const rootReducer = combineReducers({
    theDefaultReducer,
    firstNamedReducer,
    secondNamedReducer
  });

作用,把reducers合成同一个

复制代码
//定义类型略
//错误处理代码略
export default function combineReducers(reducers: ReducersMapObject) {
  //获取key const reducerKeys
= Object.keys(reducers) const finalReducers: ReducersMapObject = {} for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] if (process.env.NODE_ENV !== 'production') { if (typeof reducers[key] === 'undefined') { warning(`No reducer provided for key "${key}"`) } } if (typeof reducers[key] === 'function') {
    //设定value finalReducers[key] =
reducers[key] } } const finalReducerKeys = Object.keys(finalReducers) // This is used to make sure we don't warn about the same // keys multiple times. let unexpectedKeyCache: { [key: string]: true } if (process.env.NODE_ENV !== 'production') { unexpectedKeyCache = {} } let shapeAssertionError: Error try { assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e }   //返回的combinedreducer return function combination( state: StateFromReducersMapObject<typeof reducers> = {}, action: AnyAction ) { if (shapeAssertionError) { throw shapeAssertionError } if (process.env.NODE_ENV !== 'production') { const warningMessage = getUnexpectedStateShapeWarningMessage( state, finalReducers, action, unexpectedKeyCache ) if (warningMessage) { warning(warningMessage) } } let hasChanged = false const nextState: StateFromReducersMapObject<typeof reducers> = {}
  //遍历来比较
for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key]
  //获取新的state const nextStateForKey
= reducer(previousStateForKey, action) if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey
  //判断state的值有没有改变 hasChanged
= hasChanged || nextStateForKey !== previousStateForKey }
  //判断key有没有改变 hasChanged
= hasChanged || finalReducerKeys.length !== Object.keys(state).length
  //如果有改变返回新state
return hasChanged ? nextState : state } }
复制代码

 bindActionCreators .ts

文档: 惟一会使用到 bindActionCreators 的场景是当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 dispatch或 Redux store 传给它。

把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch 对每个 action creator 进行包装,以便可以直接调用它们。

一般情况下你可以直接在 Store 实例上调用 dispatch。如果你在 React 中使用 Redux,react-redux 会提供 dispatch 函数让你直接调用它 。

复制代码
export default function bindActionCreators(
  actionCreators: ActionCreator<any> | ActionCreatorsMapObject,
  dispatch: Dispatch
) {
  //function type
if (typeof actionCreators === 'function') { return bindActionCreator(actionCreators, dispatch) }    if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error( `bindActionCreators expected an object or a function, instead received ${ actionCreators === null ? 'null' : typeof actionCreators }. ` + `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?` ) }  //默认,如果是包含function的{} const boundActionCreators: ActionCreatorsMapObject = {} for (const key in actionCreators) { const actionCreator = actionCreators[key] if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) } } return boundActionCreators }

  function bindActionCreator<A extends AnyAction = AnyAction>( actionCreator: ActionCreator<A>, dispatch: Dispatch ) {
    return function(this: any, ...args: any[]) {
      return dispatch(actionCreator.apply(this, args))
  }
}
 
复制代码

 

 

posted @   Esther_Cheung  阅读(370)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示