版本:v4.0.0
html
后续内容更新,请前往:我的博客,欢迎一块儿交流。前端
受2014年Facebook的Flux架构模式
以及函数式编程语言Elm
启发,Dan Abramov在2015年建立了 Redux。很快,Redux因其体小精悍(只有2kB)且没有任何依赖短期内成为最热门的前端架构。webpack
Redux 是可预测的状态管理框架,它很好的解决多交互,多数据源的诉求。Redux 设计之初,做者就严格遵循三个设计理念原则:
单一数据源:整个应用的 state 都被储存在一棵 object tree 中,而且这个 object tree 只存在于惟一一个 store 中。store 能够看作是数据存储的一个容器,在这个容器里面,只会维护惟一一个 state tree。store 会给定4种基础操做API:dispatch(action),getState(),replaceReducer(nextReducer),subscribe(listener)
。根据单一数据源原则,全部数据会经过store.getState()
方法调用获取。
state只读:根据 state 只读原则,数据变动会经过 store,dispatch(action) 方法,Action 能够理解为变动数据的信息载体,type 是变动数据的惟一标志,payload 是用来携带须要变动的数据,格式大体为:const action = { type: 'xxx', payload: 'yyy' }
;Reducer 是个纯函数,负责根据 action.type 获取须要变动的数据,而后计算 state 数值。格式为:reducer: prevState => action => newState
。
使用纯函数变动state值:Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。git
正常的一个同步数据流为:view 层触发 actionCreator,actionCreator 经过 store.dispatch(action) 方法变动 reducer。可是面对多种多样的业务场景,同步数据流方式显然没法知足。对于改变reducer的异步数据操做,就须要用到中间件的概念,如图所示:github
在开始以前咱们先作如下几点约定:
第一:目前分析的版本是 redux 的最新版本 4.0.0;
第二:我尽量站在我本身的角度去剖析,固然我会借鉴社区比较优秀的文章,欢迎与你们一块儿交换意见,努力写好该 redux 源码系列;
第三:若是有幸您读到该 redux 源码系列,感受写得还行,还望收藏、分享或打赏。web
Redux 的源码结构很简单,源码都在 src 目录下,其目录结构以下:编程
src ├── utils ---------------------------------------- 工具函数 ├── applyMiddleware.js --------------------------- 加载 middleware ├── bindActionCreators.js ------------------------ 生成将 action creator 包裹在 dispatch 里的函数 ├── combineReducers.js --------------------------- 合并 reducer 函数 ├── compose.js ----------------------------------- 组合函数 ├── createStore.js ------------------------------- 建立一个 Redux store 来储存应用中全部的 state ├── index.js ------------------------------------- 入口 js
index.js 是整个代码的入口,其代码以下:redux
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' function isCrushed() {} if ( process.env.NODE_ENV !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed' ) { warning( 'You are currently using minified code outside of NODE_ENV === "production". ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' + 'to ensure you have the correct code for your production build.' ) } export { createStore, combineReducers, bindActionCreators, applyMiddleware, compose, __DO_NOT_USE__ActionTypes }
入口代码很简单,首先isCrushed
函数主要是为了验证在非生产环境下Redux
是否被压缩?若是被压缩了,isCrushed.name !== 'isCrushed'
就等于 true
,这样就会给开发者一个warn
提示。最后暴露createStore
、combineReducers
、bindActionCreators
、applyMiddleware
、compose
这几个接口给开发者使用,接下来咱们逐一解析这几个 API。api
createStore.js 是 Redux 最重要的一个 API ,它负责建立一个 Redux store 来储存应用中全部的 state,整个应用中应有且仅有一个 store。如今咱们来看一下 createStore 源代码:数组
import $$observable from 'symbol-observable' // 私有 action import ActionTypes from './utils/actionTypes' import isPlainObject from './utils/isPlainObject' export default function createStore(reducer, preloadedState, enhancer) { // 判断接受的参数个数,来指定 reducer、preloadedState 和 enhancer if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } // 若是 enhancer 存在且是个合法的函数,就调用 enhancer,不然抛出错误提示 if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) } if (typeof reducer !== 'function') { throw new Error('Expected the reducer to be a function.') } // 储存当前的 currentReducer let currentReducer = reducer // 储存当前的状态 let currentState = preloadedState // 储存当前的监听函数列表 let currentListeners = [] // 储存下一个监听函数列表 let nextListeners = currentListeners let isDispatching = false // 这个函数能够根据当前监听函数的列表生成新的下一个监听函数列表引用 function ensureCanMutateNextListeners() { if (nextListeners === currentListeners) { nextListeners = currentListeners.slice() } } // 读取由 store 管理的状态树 function getState() { 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 } function subscribe(listener) { // 判断传入的参数是否为函数 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#subscribe(listener) for more details.' ) } let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) 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#subscribe(listener) for more details.' ) } isSubscribed = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } } function dispatch(action) { if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } // 判断 action 是否有 type{必须} 属性 if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } // 若是正在 dispatch 则抛出错误 if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } // 对抛出 error 的兼容,可是不管如何都会继续执行 isDispatching = false 的操做 try { isDispatching = true // 使用 currentReducer 来操做传入 当前状态和 action,放回处理后的状态 currentState = currentReducer(currentState, action) } finally { isDispatching = false } const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action } // 判断参数是不是函数类型 function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer dispatch({ type: ActionTypes.REPLACE }) } function observable() { const outerSubscribe = subscribe return { subscribe(observer) { if (typeof observer !== 'object' || observer === null) { throw new TypeError('Expected the observer to be an object.') } function observeState() { if (observer.next) { observer.next(getState()) } } observeState() const unsubscribe = outerSubscribe(observeState) return { unsubscribe } }, [$$observable]() { return this } } } dispatch({ type: ActionTypes.INIT }) return { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } }
这里咱们首先要讲一下ActionTypes
对象,它是 Redux 的私有 action,不容许外界触发,用来初始化 store 的状态树和改变 reducers 后初始化 store 的状态树。接下来咱们从不一样角度着重来说一下 createStore 函数:
它能够接受三个参数:reducer、preloadedState、enhancer:
reducer:函数,返回下一个状态,接受两个参数:当前状态 和 触发的 action;
preloadedState:它是 state 的初始值,能够随意指定,好比服务端渲染的初始状态,可是若是使用 combineReducers 来生成 reducer,那必须保持状态对象的 key 和 combineReducers 中的 key 相对应,另外实际上它并不只仅是扮演着一个 initialState 的角色,若是咱们第二个参数是函数类型,createStore 会认为咱们忽略了 preloadedState 而传入了一个enhancer;
enhancer:可选参数,一个组合 store creator 的高阶函数,能够翻译成 store 的加强器,顾名思义,就是加强 store 的功能。通常指定为第三方的中间件,时间旅行,持久化等等,返回一个新的强化过的 store creator,这个函数一般用 Redux 提供的 applyMiddleware 函数来生成。
根据传入参数的个数和类型,判断 reducer、preloadedState、enhancer。
调用完函数的返回值:dispatch、subscribe、getState、replaceReducer 和 [$$observable],这就是咱们开发中主要使用的几个接口。
若是enhancer
参数存在且是个合法的函数,那么就调用enhancer
函数。enhancer
其实是一个高阶函数,它的参数是建立store
的函数createStore
,返回值是一个能够建立功能更增强大的store
的函数(enhanced store creator),这和 React 中的高阶组件的概念很类似。store enhancer 函数的结构通常以下:
function enhancerCreator() { return createStore => (...args) => { // do something based old store // return a new enhanced store } }
注意,enhancerCreator
是用于建立enhancer store
的函数,也就是说enhancerCreator
的执行结果才是一个enhancer store
。...args
参数表明建立store
所需的参数,也就是createStore
接收的参数,实际上就是(reducer, [preloadedState], [enhancer])
。
如今,咱们来建立一个enhancer store
,用于输出发送的action
的信息和state
的变化:
// logging.js(store enhancer) export default function logging() { return createStore => (reducer, initialState, enhancer) => { const store = createStore(reducer, initialState, enhancer) function dispatch(action) { console.log(`dispatch an action: ${JSON.stringify(action)}`); const res = store.dispatch(action); const newState = store.getState(); console.log(`current state: ${JSON.stringify(newState)}`); return res; } return {...store, dispatch} } }
logging()
改变了store dispatch
的默认行为,在每次发送action
先后,都会输出日志信息,而后在建立store
上,使用logging()
这个store enhancer:
// store.js import { createStore, combineReducers } from 'redux'; import * as reducer from '../reducer'; import logging from '../logging'; //建立一个 Redux store 来以存放应用中全部的 state,应用中应有且仅有一个 store。 var store = createStore( combineReducers(reducer), logging() ); export default store;
// 读取由 store 管理的状态树 function getState() { 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 }
这个函数能够获取当前的状态,createStore 中的 currentState 储存当前的状态树,这是一个闭包,这个参数会持久存在,而且全部的操做状态都是改变这个引用,getState 函数返回当前的 currentState。
function subscribe(listener) { // 判断传入的参数是否为函数 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#subscribe(listener) for more details.' ) } let isSubscribed = true ensureCanMutateNextListeners() nextListeners.push(listener) 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#subscribe(listener) for more details.' ) } isSubscribed = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } }
这个函数能够给 store 的状态添加订阅监听函数,一旦调用dispatch
,全部的监听函数就会执行;nextListeners
就是储存当前监听函数的列表,调用subscribe
,传入一个函数做为参数,那么就会给nextListeners
列表push
这个函数;同时调用subscribe
函数会返回一个unsubscribe
函数,用来解绑当前传入的函数,同时在subscribe
函数定义了一个isSubscribed
标志变量来判断当前的订阅是否已经被解绑,解绑的操做就是从nextListeners
列表中删除当前的监听函数。
function dispatch(action) { if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } // 判断 action 是否有 type{必须} 属性 if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } // 若是正在 dispatch 则抛出错误 if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } // 对抛出 error 的兼容,可是不管如何都会继续执行 isDispatching = false 的操做 try { isDispatching = true // 使用 currentReducer 来操做传入 当前状态和 action,放回处理后的状态 currentState = currentReducer(currentState, action) } finally { isDispatching = false } const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action }
这个函数是用来触发状态改变的,它接受一个 action 对象做为参数,而后 reducer 根据 action 的属性以及当前 store 的状态来生成一个新的状态,赋予当前状态,改变 store 的状态;即currentState = currentReducer(currentState, action)
;这里的currentReducer
是一个函数,它接受两个参数:当前状态 和 action,而后返回计算出来的新的状态;而后遍历nextListeners
列表,调用每一个监听函数。
// 判断参数是不是函数类型 function replaceReducer(nextReducer) { if (typeof nextReducer !== 'function') { throw new Error('Expected the nextReducer to be a function.') } currentReducer = nextReducer dispatch({ type: ActionTypes.REPLACE }) }
这个函数能够替换 store 当前的 reducer 函数,首先直接用currentReducer = nextReducer
替换;而后dispatch({ type: ActionTypes.INIT })
,用来初始化替换后 reducer 生成的初始化状态而且赋予 store 的状态。
function observable() { const outerSubscribe = subscribe return { subscribe(observer) { if (typeof observer !== 'object' || observer === null) { throw new TypeError('Expected the observer to be an object.') } function observeState() { if (observer.next) { observer.next(getState()) } } observeState() const unsubscribe = outerSubscribe(observeState) return { unsubscribe } }, [$$observable]() { return this } } }
对于这个函数,是不直接暴露给开发者的,它提供了给其余观察者模式/响应式库的交互操做。
最后执行dispatch({ type: ActionTypes.INIT })
,用来根据 reducer 初始化 store 的状态。
compose
能够接受一组函数参数,而后从右到左来组合多个函数(这是函数式编程中的方法),最后返回一个组合函数。如今咱们来看一下 compose 源代码:
/** * For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))). */ export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }
compose
其做用是把一系列的函数,组装生成一个新的函数,而且从后到前,后面参数的执行结果做为其前一个的参数,当须要把多个 store 加强器 依次执行的时候,须要用到它。
(...funcs):须要合成的多个函数。每一个函数都接收一个函数做为参数,而后返回一个函数。
(Function):从右到左把接收到的函数合成后的最终函数。
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.
这是 redux 做者 Dan 对 middleware 的描述,middleware 提供了一个分类处理 action 的机会,在 middleware 中咱们能够检阅每个流过的 action,挑选出特定类型的 action 进行相应操做,给咱们改变 action 的机会。
Redux middleware 的设计十分特殊,是一个层层包裹的匿名函数,实际上这是函数式编程中的柯里化,一种使用匿名单参数函数来实现多参数函数的方法,柯里化的 middleware 结构好处在于:
一:易串联,柯里化函数具备延迟执行的特性,经过不断柯里化造成的 middleware 能够累积参数,配合组合的方式,很容易造成 pipeline 来处理数据流。
二:共享 store,在 applyMiddleware 执行过程当中,store 仍是旧的,可是由于闭包的存在,applyMiddleware 完成后,全部的 middlewares 内部拿到的 store 是最新且相同的。
redux 提供了 applyMiddleware 这个 api 来加载 middleware。如今咱们来看一下 applyMiddleware 源代码:
import compose from './compose' export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } // 暴漏 getState 和 dispatch 供第三方中间件使用 const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // middlewareAPI 做为每一个 middleware 的参数依次执行一遍,最终返回函数组成的数组 const chain = middlewares.map(middleware => middleware(middlewareAPI)) // 用 compose 组合函数生成新的 dispatch dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
由上咱们能够发现 applyMiddleware 的结构也是一个多层柯里化的函数,借助 compose,applyMiddleware 能够用来和其余插件一块儿增强 createStore 函数。
咱们在 createStore 小节中其实就用说起过 applyMiddleware:
// 若是 enhancer 存在且是个合法的函数,就调用 enhancer,不然抛出错误提示 if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) }
这里 enhancer 其实就等于 applyMiddleware(mid1, mid2, mid3, ...),所以咱们建立一个 store 实际上就变成以下方式了:
applyMiddleware(mid1, mid2, mid3, ...)(createStore)(reducer, preloadedState);
由上述代码可知 applyMiddleware 陆续能够接受四个参数:
[md1, mid2, mid3, ...]: middlewares 数组;
createStore:Redux 原生的 createStore;
reducer:函数,返回下一个状态;
preloadedState:state 的初始值。
接下来,咱们看一下 applyMiddleware 用这些参数都作了什么?
const store = createStore(...args) const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
applyMiddleware 利用 createStore 和 (reducer, preloadedState) 建立了一个 store,而后 store 的 getState 方法和 dispatch 方法又分别赋值给 middlewareAPI 变量,紧接着用 middlewareAPI 做为每一个 middleware 的参数依次执行一遍,执行完后,最终得到数组 chain:[f1, f2, ..., fn] 交给组合函数 compose 处理。compose 能够接受一组函数参数,而后从右到左来组合多个函数(这是函数式编程中的方法),最后返回一个组合函数,例如:
// 调用 dispatch = compose(f, g, h)(store.dispatch) // 返回 dispatch = f(g(h(store.dispatch)))
这样经过调用新的 dispatch,每一个 middleware 的代码就能够依次执行了。
store:原来的store;
dispatch:改变后的dispatch。
Reducer 是管理 state 的一个模块,它主要作的事情就是当项目初始化时,返回 initalState,当用户用操做时,它会根据 action 进行相应地更新。须要注意的是它是一个纯函数,换言之,它不会改变传入的 state。如今咱们来看一下 combineReducers 源码(源码有删减,删除了一些验证代码):
import ActionTypes from './utils/actionTypes' import warning from './utils/warning' import isPlainObject from './utils/isPlainObject' export default function combineReducers(reducers) { // 根据 reducers 生成最终合法的 finalReducers:value 为 函数 const reducerKeys = Object.keys(reducers) const finalReducers = {} 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') { finalReducers[key] = reducers[key] } } const finalReducerKeys = Object.keys(finalReducers) let unexpectedKeyCache if (process.env.NODE_ENV !== 'production') { unexpectedKeyCache = {} } let shapeAssertionError try { assertReducerShape(finalReducers) } catch (e) { shapeAssertionError = e } // 返回最终生成的 reducer return function combination(state = {}, action) { 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 = {} for (let i = 0; i < finalReducerKeys.length; i++) { const key = finalReducerKeys[i] const reducer = finalReducers[key] const previousStateForKey = state[key] const nextStateForKey = reducer(previousStateForKey, action) if (typeof nextStateForKey === 'undefined') { const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage) } nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey !== previousStateForKey } // 遍历一遍验证下是否改变,而后返回原有状态值或者新的状态值 return hasChanged ? nextState : state } }
该函数最终返回 combination 函数,它就是真正 createStore 函数的 reducer,接受一个初始化状态和一个 action 参数;该函数每次调用大体执行如下几个操做:
一、for (let i = 0; i < finalReducerKeys.length; i++) { ... }:
遍历 finalReducer(有效的 reducer 列表);
二、var previousStateForKey = state[key]:
当前遍历项的以前状态,看到这里就应该明白传入的 reducers
组合为何 key
要和 store 里面的 state 的 key
相对应了;
三、var nextStateForKey = reducer(previousStateForKey, action):
当前遍历项的下一个状态;
四、nextState[key] = nextStateForKey:
将 当前遍历项的下一个状态添加到 nextState;
五、hasChanged = hasChanged || nextStateForKey !== previousStateForKey:
判断状态是否改变;
六、return hasChanged ? nextState : state:
若是没有改变就返回原有状态,若是改变了就返回新生成的状态对象。
reducers (Object): 一个对象,它的值(value)对应不一样的 reducer 函数,这些 reducer 函数后面会被合并成一个。
(Function):它是真正 createStore 函数的 reducer,接受一个初始化状态和一个 action 参数;每次调用的时候会去遍历 finalReducer(有效的 reducer 列表),而后调用列表中每一个 reducer,最终构造一个与 reducers 对象结构相同的 state 对象。
Redux 中的 bindActionCreators 是经过 dispatch 将 action 包裹起来,这样就能够经过 bindActionCreators 建立方法调用 dispatch(action)。如今咱们来看一下 bindActionCreators 源代码:
function bindActionCreator(actionCreator, dispatch) { return function() { return dispatch(actionCreator.apply(this, arguments)) } } export default function bindActionCreators(actionCreators, dispatch) { // 若是是一个函数,直接返回一个 bindActionCreator 函数,即调用 dispatch 触发 action 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"?` ) } // 遍历对象,而后设置每一个遍历项的 actionCreator 生成函数,最后返回这个对象 const keys = Object.keys(actionCreators) const boundActionCreators = {} for (let i = 0; i < keys.length; i++) { const key = keys[i] const actionCreator = actionCreators[key] if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) } } return boundActionCreators }
由此能够看出 bindActionCreators 的实现逻辑比较简单:
1、判断传入的参数是不是 object,若是是函数,就直接返回一个将 action creator 包裹在 dispatch 里的函数。
2、若是是object,就根据相应的key,生成相应的将 action creator 包裹在 dispatch 里的函数。
为了方便理解,咱们用一个 TODO 例子说明下:
// actions/todo.js export function addTodo(text) { return { type: 'ADD_TODO', text } } export function removeTodo(id) { return { type: 'REMOVE_TODO', id } }
咱们 import 后会获得以下对象:
{ addTodo : text => { type: 'ADD_TODO', text }, removeTodo : id => { type: 'REMOVE_TODO', id } }
通过 bindActionCreator 就会变成 key 相同,值为用 dispatch 将 action creator 包裹起来的函数的对象:
{ addTodo : text => dispatch(addTodo('text')); removeTodo : id => dispatch(removeTodo('id')); }
由此咱们发现能够经过 bindActionCreators 建立方法直接调用 dispatch(action)。
它能够接收两个参数:actionCreators、dispatch
actionCretors:能够是一个对象,也能够是一个单个函数
dispatch:dispatch 函数,从 store 实例中获取,用于包裹 action creator
若是只是传入一个 function,返回的也是一个 function,例如:
// actions/todo.js export const toggleTodo = (id) => { return { type: 'TOGGLE_TODO', id }; };
通过 bindActionCreator:
const boundActionCreators = bindActionCreators(toggleTodo, dispatch);
因为 bindActionCreators 第一个参数是一个函数,结果就会变为:
const boundActionCreators = (id) => dispatch(toggleTodo(id));
单个函数,或者是一个对象。
经过阅读 Redux 的源码,咱们发现 Redux 设计的实在是太精妙了,彻底函数式编程,依赖少,耦合低。