乐趣区

关于javascript:Redux源码解读

一、Redux 的性能是什么?

  • 将状态对立放在一个 state 中,由 store 来治理这个 state
  • 这个 store 依照 reducer 的“shape”(形态)创立。
  • reducer 的作用是接管到 action 后,输入一个新的状态,对应地更新 store 上的状态。
  • 依据 redux 的准则领导,内部扭转 state 的最佳形式是通过调用 store 的 dispatch 办法,触发一个 action,这个 action 被对应的 reducer 解决,实现 state 更新。
  • 能够通过 subscribe 在 store 上增加一个监听函数。每当调用 dispatch 办法时,会执行所有的监听函数。
  • 能够增加中间件(middleware)解决副作用。

这个过程中,Redux 须要提供的性能是:

  • 创立 store,即:createStore()
  • 创立进去的 store 提供 subscript,dispatch,getState,replaceReducer 这些办法
  • 将多个 reducer 合并为一个 reducer,即:combineReducers()
  • 利用中间件,即 applyMiddleware()

二、Redux 源码构造

这就是 Redux 的源码构造:

这里有下面所说的 applyMiddleware.ts、combineReducers.ts、createStore.ts,至于 compose.ts 和 bindActionCreators.ts 则是一些工具,前面会讲到。

1.compose.ts

其实说白了,compose()这个函数的作用就是:

const func = [f1, f2, f3];
compose(...func)        //return f1(f2(f3(...args)))
// 留神函数调用的程序是从左到右,即:f1 -> f2 -> f3

上面是 compose()的源码:

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
  }

  if (funcs.length === 1) {return funcs[0]
  }

  return funcs.reduce((a, b) => (...args: any) => a(b(...args)))
}

其实换成这样更好了解:

export default function compose(...funcs) {if (funcs.length === 0) {return arg => arg}

  if (funcs.length === 1) {return funcs[0]
  }

  const last = funcs[funcs.length - 1]
  const rest = funcs.slice(0, -1)
  return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}

其实最要害就是这句话:

return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));

reduceRight()就是 reduce()的倒序执行,也就是 reduce() 是从左到右执行,reduceRight()是从右到左执行

2.createStore.ts

这个函数大抵是这样的:

function createStore(reducer, preloadedState, enhancer) {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
    }
  
      if (typeof reducer !== 'function') {throw new Error('Expected the reducer to be a function.')
    }
    
    let currentReducer = reducer // 以后 store 中的 reducer
    let currentState = preloadedState // 以后 store 中存储的状态
    let currentListeners = [] // 以后 store 中搁置的监听函数
    let nextListeners = currentListeners // 下一次 dispatch 时的监听函数
    // 留神:当咱们新增加一个监听函数时,只会在下一次 dispatch 的时候失效。//...
    
    // 获取 state
    function getState() {//...}
    
    // 增加一个监听函数,每当 dispatch 被调用的时候都会执行这个监听函数
    function subscribe() {//...}
    
    // 触发了一个 action,因而咱们调用 reducer,失去的新的 state,并且执行所有增加到 store 中的监听函数。function dispatch() {//...}
   
    //...
    
    //dispatch 一个用于初始化的 action,相当于调用一次 reducer
    // 而后将 reducer 中的子 reducer 的初始值也获取到
    // 详见上面 reducer 的实现。return {
        dispatch,
        subscribe,
        getState,
        // 上面两个是次要面向库开发者的办法,临时先疏忽
        //replaceReducer,
        //observable
    }
}

能够看出,createStore 办法创立了一个 store,然而并没有间接将这个 store 的状态 state 返回,而是返回了一系列办法,内部能够通过这些办法(getState)获取 state,或者间接地(通过调用 dispatch)扭转 state

createStore 总共接管三个参数:reducer, preloadState, enhancer

  • reducer: 一个纯函数,接管上一个(或初始化)state 和 action,依据 action 的 type 返回新的 state
  • preloadState: 一个初始化的 state,能够设置 store 中的默认值
  • enhance: 增强器,用于拓展 store 的性能,个别是applyMiddleWare(…middleware)

三个要害函数:
1.getState

这个没啥好说的,就是返回 currentState

function getState(): S {if (isDispatching) {// 当 reducer 执行中的时候不能应用 getState()
      //state 是通过一层一层的 reducer 传递下来的,每执行一次 reducer state 就会扭转,不能间接从 store 中读取
      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
  }

这里须要留神的是,当 reducer 执行中不能应用 getState(), 因为state 是通过一层一层的 reducer 传递下来的,每执行一次 reducer,state 就会扭转,不能间接从 store 中读取。

2.subscript

//subscribe(listener)函数源码, 返回一个勾销订阅的函数,//let unsubscribe = subscribe(listener);     // 给 listener 函数增加了订阅
//unsubcribe()     // 给 listener 函数勾销订阅
// 实际上就是保护 nextListeners 数组的过程,订阅就 push,勾销订阅就 splice(index, 1);
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/store#subscribelistener for more details.'
    )
  }

  let isSubscribed = true     // 回调函数被订阅默认的标记

  ensureCanMutateNextListeners()
  nextListeners.push(listener)    // 新增订阅在 nextListeners 中操作

  // 返回一个勾销订阅的函数
  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/store#subscribelistener for more details.'
      )
    }

    isSubscribed = false            // 勾销订阅,这里将回调函数被订阅的标记设置为 false

    ensureCanMutateNextListeners()
    const index = nextListeners.indexOf(listener)
    // 因为 listener 曾经被勾销订阅了,所以在 nextListeners 将 listener 删除掉
    nextListeners.splice(index, 1)
    currentListeners = null
  }
}

(1)首先看传入的参数,是一个 listener 的回调函数 当 reducer 执行结束之后,会执行这个回调

这个是官网的解释:

listener (_Function_): The callback to be invoked any time an action has been dispatched, and the state tree might have changed. You may call getState() inside this callback to read the current state tree. It is reasonable to expect that the store’s reducer is a pure function, so you may compare references to some deep path in the state tree to learn whether its value has changed.

简略解释一下,就是 当 dispatch(action)实现的时候(应该是 reduce 执行实现的时候)会去调用 listener 这个回调函数 ,状态树可能会扭转。 能够在 listener 外面应用 getState()获取到最新的状态 。能够 通过比拟状态树中的一些深层门路的援用去判断状态的值是否产生扭转。

(2)如果 reducer 正在执行,是不能调用 subscribe 和 unsubscribe 的

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/store#subscribelistener for more details.'
  )
}

if (isDispatching) {
  throw new Error(
    'You may not unsubscribe from a store listener while the reducer is executing.' +
    'See https://redux.js.org/api/store#subscribelistener for more details.'
  )
}

我的了解是:因为 dispatch 函数会在 reducer 执行结束后循环执行 listeners 数组内订阅的更新函数,所以要保障这个时候的 listener 数组不变,既不能增加更新函数(subscribe) 也不能删除更新函数(unsubscribe)。

(3)返回一个勾销订阅的函数

// 返回一个勾销订阅的函数
return function unsubscribe() {if (!isSubscribed) {return}

  // 如果正在执行 reducer 则不能执行 unsubscribe 函数
  if (isDispatching) {
    throw new Error(
      'You may not unsubscribe from a store listener while the reducer is executing.' +
      'See https://redux.js.org/api/store#subscribelistener for more details.'
    )
  }

  isSubscribed = false

  ensureCanMutateNextListeners()
  const index = nextListeners.indexOf(listener)
  // 因为 listener 曾经被勾销订阅了,所以在 nextListeners 将 listener 删除掉
  nextListeners.splice(index, 1)
  currentListeners = null
}

(4)我对 subscribe 函数的了解:实际上就是保护 nextListeners 数组的过程,订阅就 push,勾销订阅就 splice(index, 1); 等到 dispatch 函数在 reducer 执行结束之后会循环执行 listeners 数组内订阅的更新函数。

相应的代码如下:

function ensureCanMutateNextListeners() {if (nextListeners === currentListeners) {nextListeners = currentListeners.slice()
  }
}

// 新增订阅
ensureCanMutateNextListeners()
nextListeners.push(listener)    // 新增订阅在 nextListeners 中操作

// 勾销订阅
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
// 因为 listener 曾经被勾销订阅了,所以在 nextListeners 将 listener 删除掉
nextListeners.splice(index, 1)
currentListeners = null

可见,新增订阅和勾销订阅都是在 nextListener 外面操作,不会间接在 currentListener 外面操作

咱们会发现,在每次新增订阅和勾销订阅的时候,都会先调用一个 ensureCanMutateNextListeners 函数 。这个函数的语义就是确保能够转变 nextListeners。顾名思义,这个函数本质的作用是 确保能够扭转 nextListeners, 如果 nextListeners 与 currentListeners 统一的话,将 currentListeners 做一个拷贝赋值给 nextListeners, 而后所有的操作都会集中在 nextListeners。

3.dispatch

function dispatch(action: A) {
  //action 不是原生的对象,报错
  if (!isPlainObject(action)) {
    throw new Error(
      'Actions must be plain objects.' +
      'Use custom middleware for async actions.'
    )
  }

  // 对于一个 action 来说,action 中的 type 是必须的
  if (typeof action.type === 'undefined') {
    throw new Error(
      'Actions may not have an undefined"type"property.' +
      'Have you misspelled a constant?'
    )
  }

  //reducer 正在执行的时候不能调用
  if (isDispatching) {throw new Error('Reducers may not dispatch actions.')
  }

  try {
    isDispatching = true
    //currentState 与 action 会流通到所有的 reducer
    // 所有的 reducer 的返回值整合后,替换掉以后的 currentState
    currentState = currentReducer(currentState, action)     // 这句话就是触发相应的 reducer
  } finally {isDispatching = false}

  // 最初一一触发回调函数,回调函数的执行是在 dispatch 外面
  const listeners = (currentListeners = nextListeners)
  for (let i = 0; i < listeners.length; i++) {const listener = listeners[i]
    listener()}
  
  // 为了不便链式调用,dispatch 执行结束后,返回 action
  return action
}

(1)传入的参数:一个 action

(2)接下来就是一系列的判断检测,有三点要求:

  • action 必须得是原生的对象
  • 对于一个 action 来说,action 中的 type 是必须的
  • reducer 正在执行的时候不能调用 dispatch

相应的代码如下:

//action 不是原生的对象,报错
if (!isPlainObject(action)) {
  throw new Error(
    'Actions must be plain objects.' +
    'Use custom middleware for async actions.'
  )
}

// 对于一个 action 来说,action 中的 type 是必须的
if (typeof action.type === 'undefined') {
  throw new Error(
    'Actions may not have an undefined"type"property.' +
    'Have you misspelled a constant?'
  )
}

//reducer 正在执行的时候不能调用
if (isDispatching) {throw new Error('Reducers may not dispatch actions.')
}

(3)要害局部代码:

try {
  isDispatching = true
  //currentState 与 action 会流通到所有的 reducer
  // 所有的 reducer 的返回值整合后,替换掉以后的 currentState
  currentState = currentReducer(currentState, action)     // 这句话就是触发相应的 reducer
} finally {isDispatching = false}

// 最初一一触发回调函数,回调函数的执行是在 dispatch 外面
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {const listener = listeners[i]
  listener()}

// 为了不便链式调用,dispatch 执行结束后,返回 action
return action

由下面的 dispatch 函数可见,先执行 currentReducer,再别离执行 listeners 外面的回调

// 先执行 currentReducer
currentState = currentReducer(currentState, action);
//...

// 将 nextListener 赋值给 currentListener,为的是后续的 dispatch 执行回调函数(listener)过程中,// 能够将这一轮 dispatch 新增的回调函数(newListener)执行
const listeners = (currentListeners = nextListeners);
// 最初一一触发回调函数,回调函数的执行是在 dispatch 外面
for (let i = 0; i < listeners.length; i++) {const listener = listeners[i]
  listener()}

(4)总之,dispatch 函数就干了两件事,执行了相应的 reducer,执行了 currentListener 注册的回调函数(listener)

3.combineReducers.ts

(1)外围局部源码加解释:

export default function combineReducers(reducers: ReducersMapObject) {
  // 获取到所有的 reducer 的名字,组成数组
  const reducerKeys = Object.keys(reducers)
  // 这个 finalReducers 是最终无效的 reducers
  const finalReducers: ReducersMapObject = {}
  for (let i = 0; i < reducerKeys.length; i++) {const key = reducerKeys[i]

    if (process.env.NODE_ENV !== 'production') {
      // 不是生产环境且存在对应 key 的 reducer
      if (typeof reducers[key] === 'undefined') {warning(`No reducer provided for key "${key}"`)
      }
    }

    if (typeof reducers[key] === 'function') {finalReducers[key] = reducers[key]
    }
  }
  // 做了一系列的判断之后失去了最终的 finalReducerKeys 数组
  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
  //assertReducerShape 用来查看每个 reducer 有没有默认返回的 state
  try {assertReducerShape(finalReducers)
  } catch (e) {shapeAssertionError = e}

  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
    //nextState 寄存所有的 state
    const nextState: StateFromReducersMapObject<typeof reducers> = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      // 获取每个 reducer 的名字
      const key = finalReducerKeys[i]
      // 获取每个 reducer
      const reducer = finalReducers[key]
      // 获取每个 reducer 对应的旧状态
      const previousStateForKey = state[key]
      // 调用该 reducer,依据这个 reducer 的旧状态和以后 action 来生成新的 state
      const nextStateForKey = reducer(previousStateForKey, action)    // 执行各子 reducer 以获取子 nextState
      if (typeof nextStateForKey === 'undefined') {const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      // 以各自的 reducerName 为键,新生成的 state 为值,生成最终的 state object。将子 nextState 挂载到对应的键名,将所有的子 state 合并到一个对象中
      nextState[key] = nextStateForKey
      // 比拟通过 reducer 之后的下一个状态和上一个状态是否雷同判断是否 hasChanged, 只有有一个子 state 产生扭转,整个 state 就会产生扭转
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    hasChanged =
      hasChanged || finalReducerKeys.length !== Object.keys(state).length
      // 变动了,返回新的 state,否则,返回旧的 state
    return hasChanged ? nextState : state     //combineReducers 返回的是下一个状态的汇合(如果状态扭转的话)
  }
}

(1)传入的参数:reducers: 是一个由泛滥的 reducer 组成的对象

(2)这个函数的大体思路就是:取到所有的 reducers 的 key 值 -> 通过筛选得出最终的 reducers 的 key 值组成的数组 finalReducerKeys 和所有 reducer 组成的数组 finalReducers -> 应用 finalReducers 外面的 reducer 去操作对应的 state -> 比拟 reducer 前后的 state 是否发生变化 -> 如果 state 产生了扭转,返回一个 由 reducer 名字作为键名,reducer 之后的 nextStateForKey 作为 value 的对象

4.applyMiddleware.ts

redux 本来的 dispatch 办法只能承受一个对象作为 action

用户操作 -> dispatch(action) -> reducer(prevState, action) -> 新的 state -> 界面

如果 页面要发送申请数据,而且要把数据放在 action 外面,最终通过 reducer 的解决,放到 store 中。这时就须要用到 middleware 了。

用户操作 -> dispatch(action) -> middleware(action) -> 真正的 action -> reducer(prevState, action) -> 新的 state -> 界面

这里是在 dispatch(action)之后增加了中间件解决,将数据放在 action 中,返回一个新的 action。

applyMiddleware 大抵会这样应用:

const store = createStore(rootReducer, applyMidddleWare(thunk))

applyMiddleWare(thunk)就相当于一个 enhancer,负责拓展 redux,说白了就是拓展 store 的 dispatch 办法。这个又怎么解释呢?到底是通过什么样的形式去拓展 dispatch 呢?

上面我应用一个革新版的 applyMiddleware 办法和 redux-thunk 的外围代码 createThunkMiddleware 一起来形容一下是如何实现 dispatch 的革新的

(1)redux-thunk 的外围代码:createThunkMiddleware

// 其实这是一个 middleware
function createThunkMiddleware(extraArgument) {return ({ dispatch, getState}) => next => action => {if (typeof action === 'function') {return action(dispatch, getState, extraArgument);
    }
    //next 是被 thunk 革新之前的 dispatch,也就是说有可能是最原始的 dispatch,也有可能是被其余的中间件革新过的 dispatch
    return next(action);
  };
}
//thunk 是真正的中间件函数
const thunk = createThunkMiddleware();

// 将函数柯里化写成嵌套的模式
function createThunkMiddleware(extraArgument) {
  // 真正的中间件函数
  return function({dispatch, getState}) {
    // 革新 dispatch 的函数,这里的 next 是内部传进来的 dispatch,可能是被其余的中间件解决过的,也可能是最本来的
    return function(next) {
      // 返回一个新革新的 dispatch 函数
      return function(action) {
        // 如果 action 是函数,那么执行它,并且将 store 的 dispatch 和 getState 传入,// 便于咱们 dispatch 的函数外部逻辑执行完之后 dispatch 真正的 action
        if(typeOf action === 'function') {return action(dispatch, getState, extraArgument);
        }
        // 如果是一个一般的 action(也就是对象),间接 dispatch
        return next(action);
      }
    }
  }
}

const thunk = createThunkMiddleware();
  • 真正调用的时候,实践上是这样:thunk({dispatch, getState})(next)(action),其中,thunk({dispatch, getState})(next)这部分,返回的是一个承受参数为 action 的革新过后 dispatch 函数,而这部分会在 applyMiddleware 中去调用
  • next 则是被以后中间件革新之前的 dispatch。能够是最原始的 dispatch,也有可能是被其余中间件革新过的 dispatch。

(2)再看一下简易版的 applyMiddleware 办法:

function applyMiddleware(store, middlewares) {middlewares = middlewares.slice()
  middlewares.reverse()
  let dispatch = store.dispatch
  // 感觉这里十分奇妙,相当于是链式调用了 middleware 函数,返回的 dispatch 是通过所有的中间件革新过后的 dispatch 办法
  // 相似于这样 dispatch = middleware2(store)(middleware1(store)(store.dispatch))
  middlewares.forEach(middleware => (dispatch = middleware(store)(dispatch)))
  // 返回一个 dispatch 更新的 store
  return Object.assign({}, store, { dispatch})
}

这与 Redux 中 applyMiddleware() 的实现曾经很靠近了,然而 有三个重要的不同之处

  • 它只裸露一个 store API 的子集给 middleware:dispatch(action) 和 getState();
  • 它用了一个十分奇妙的形式,以确保如果你在 middleware 中调用的是 store.dispatch(action) 而不是 next(action),那么这个操作会再次遍历蕴含以后 middleware 在内的整个 middleware 链。这对异步的 middleware 十分有用;
  • 为了保障你只能利用 middleware 一次,它作用在 createStore() 上而不是 store 自身 。因而 它的签名不是 (store, middlewares) => store,而是 (…middlewares) => (createStore) => createStore

(3)最初回归到 applyMiddleware 的源码

export default function applyMiddleware(...middlewares: Middleware[]
): StoreEnhancer<any> {return (createStore: StoreCreator) => <S, A extends AnyAction>(
    reducer: Reducer<S, A>,
    ...args: any[]) => {const store = createStore(reducer, ...args)
    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)
    }
    // 假如咱们只是用了 redux-thunk, 那么此时的 middleware 就相当于 thunk,就是 function({dispatch, getState})
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 这里的 compose 的作用就是,将所有的中间件函数串联起来,中间件 1 完结,作为参数传入中间件 2,被它解决,// 以此类推,最终返回的是被所有的中间件解决完的函数,最开始承受 store.dispatch 为参数,层层革新后被赋值到新的 dispatch 变量中
    dispatch = compose<typeof dispatch>(...chain)(store.dispatch)

        // 返回的是一个将通过中间件革新的 dispatch 笼罩原有的 dispatch 的 store 对象
    return {
      ...store,
      dispatch
    }
  }
}

这里要留神的点是

  • 假如咱们只是用了一个 middleware(redux-thunk),就能够临时抛开 compose,那么这里的逻辑就相当于
dispatch = thunk(middlewareAPI)(store.dispatch);

在这里,thunk(middlewareAPI)其实返回的是一个革新 dispatch 的函数 thunk(middlewareAPI)(store.dispatch) 返回的就是被革新后的 dispatch

  • 加上 compose 也很好了解,假如有三个 middleware,别离命名为 middleware1,middleware2,middleware3,其实:dispatch = compose<typeof dispatch>(…chain)(store.dispatch)执行的过程如下:
// 先转化为 js
dispatch = compose(...chain)(store.dispatch);

// 假如 middlewares 为[middleware1, middleware2, middleware3], 则 chains 为://[middleware1(getState, dispatch), middleware2(getState, dispatch), middleware3(getState, dispatch)]
// 则下面这句代码其实是这样执行
//chains 简化为:[chains1, chains2, chain3]
chain1(chain2(chain3(store.dispatch)))        // 返回的是通过 chain3, chain2, chain1 解决过的 dispatch 函数

返回的是 通过 chain3, chain2, chain1 解决过的 dispatch 函数

所以,这里就将 store 的 dispatch 办法革新实现了,最初用革新好的 dispatch 笼罩原来 store 中的 dispatch。

总结一下 middleware 和 applyMiddleware 的关系:

  • 中间件(middleware)会帮忙咱们革新原来 store 的 dispatch 办法;
  • applyMiddleware 会 将多个 middleware 串联起来,链式调用,返回一个通过泛滥 middleware 革新过的最终的 dispatch 办法 。最初 将这个革新好的 dispatch 利用到 store 上 (相当于是 将原来的 dispatch 替换为革新好的 dispatch),返回这个更新的 store 对象

5.bindActionCreators.ts

这个 API 没啥好讲的,其实也就是做了一件事:就是给每一个 ActionCreator 加上了 dispatch,就是这样:dispatch(ActionCreator(xxx))

外围局部源码:

const boundActionCreators: ActionCreatorsMapObject = {}
  for (const key in actionCreators) {const actionCreator = actionCreators[key]
    if (typeof actionCreator === 'function') {boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)     // 为 actioncreator 一一加装上 dispatch 技能
      // 调用:actionCreators.addTodo(content) 相当于 dispatch(addTodo);
    }
  }
return boundActionCreators

应用

bindActionCreator(actionCreators, dispatch)            //actionCreators 是一个蕴含 actionCreator 的对象,dispatch 是指 store.dispatch
  • 参数:

    actionCreators (_Function_ or _Object_): 一个 action creator,或者一个 value 是 action creator 的对象。

    dispatch (_Function_): 一个由 Store 实例提供的 dispatch 函数。

  • 返回值:
    (_Function_ or _Object_): 一个与原对象相似的对象,只不过这个对象的 value 都是会间接 dispatch 原 action creator 返回的后果的函数。如果传入一个独自的函数作为 actionCreators,那么返回的后果也是一个独自的函数。

三、redux 和 flux 的区别

redux:

次要解决了 组件间状态共享的问题,原理是集中式治理 ,次要有 三个外围办法:action,store,reducer。工作流程是view 调用 store 的 dispatch 接管 action 传入 store,reducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据

flux:

flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是 view 收回一个 action,派发器接管 action,让 store 进行数据更新,更新实现当前 store 收回 change,view 承受 change 更新视图。

二者区别:

次要区别在于 flux 有多个能够扭转利用状态的 store 在 Flux 中 dispatcher 被用来传递数据到注册的回调事件 然而在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 dispatcher 合并,构造更加简略清晰。

三、总结

我对 redux 的了解:redux 就是创立一个 store 来治理所有状态,触发 action 来扭转 store

退出移动版