redux 源码浅析 (3)

就如他的名字, 是用来组合函数的, 接受刀哥函数, 返回执行的最终函数:

// 这里常用来 链接多个中间件 const store = createStore( reducer, compose(applyMiddleware(thunk), DevTools.instrument()) ) 源码解析

他的源码也很简单:

function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } // 上面都是 控制, 参数数量为 0 和 1 的情况 // 这里是重点, 将循环接收到的函数数组 return funcs.reduce((a, b) => (...args) => a(b(...args))) }

我们将 reduce 的运行再度装饰下:

// reduce 中没有初始值的时候, 第一个 `prevValue` 是取 `funcs[0]` 的值 funcs.reduce((prevValue, currentFunc) => (...args) => prevValue(currentFunc(...args)))

reducer 返回的就是 这样一个函数 (...args) => prevValue(currentFunc(...args)), 一层一层嵌套成一个函数

举一个简单的输入例子:

var foo = compose(val => val + 10, () => 1)

foo 打印:

(...args) => a(b(...args))

执行 foo() , 返回 11

applyMiddleware 使用

applyMiddleware 是使用在 createStore 中的 enhancer 参数来增强 redux 的作用

可兼容多种三方插件, 例如 redux-thunk, redux-promise, redux-saga 等等

这里使用官网的一个例子作为展示:

function logger({getState}) { // next 就是真正的 store.dispatch return next => action => { console.log('will dispatch', action) const returnValue = next(action) console.log('state after dispatch', getState()) return returnValue } } const store = createStore(rootReducer, { counter: {value: 12345} }, applyMiddleware(logger)) 源码解析 default function applyMiddleware(...middlewares) { return createStore => (...args) => { // 因为使用了 enhancer 参数, 他的内部没有 createStore 的东西, 所以这里需要重新 createStore const store = createStore(...args) let dispatch = () => { // 在中间件中 不允许使用 dispatch throw new Error( // 省略报错... ) } // 这是要传递的参数 const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // 重新 map 所有 middlewares 返回需要的结果 const chain = middlewares.map(middleware => middleware(middlewareAPI)) // 这里就是我们上面的 compose 相关的代码, 返回的结果 再次执行 得到真正的 dispatch dispatch = compose(...chain)(store.dispatch) // 返回 store 和 dispatch return { ...store, dispatch } } }

这里我们需要重新捋一捋函数的执行, 中间件以上述的 logger 为例子

applyMiddleware(logger) -> 返回的是一个函数(createStore) => (...args) => {/*省略*/} 我把他记为中间件函数 1
也就是说 applyMiddleware(logger) === (createStore) => (...args) => {/*省略*/}

这个函数将在 createStore 中使用 enhancer(createStore)(reducer, preloadedState) 这里的 enhancer 就是中间件函数 1 通过 createStore
的执行我们可以发现
store === createStore(reducer, preloadedState, enhancer) === enhancer(createStore)(reducer, preloadedState)
=== applyMiddleware(logger)(createStore)(reducer, preloadedState)
=== ((createStore) => (...args) => {/*省略*/})(createStore)(reducer, preloadedState)
=== 中间件函数 1 中的{/*省略*/} 返回结果 通过这一层的推论我们可以得出 store === 中间件函数 1中的 {/*省略*/} 返回结果

bindActionCreators 使用

这个 API 主要是用来方便 dispatch 的 他接受 2 个参数 , 第一个是对象或函数, 第二个就是 dispatch 返回值的类型很第一个参数相同

首先我们要定义创建 action 的函数

function increment(value) { return { type: 'counter/incremented', payload: value } } function decrement(value) { return { type: 'counter/decremented', payload: value } }

使用情况 1:

function App(props) { const {dispatch} = props // 因为在 hooks 中使用 加上了 useMemo const fn = useMemo(() => bindActionCreators(increment, dispatch), [dispatch]) return ( <div className="App"> <div> val: {props.value} </div> <button onClick={() => { fn(100) }}>plus </button> </div> ); }

使用情况 2:

function App(props) { const {dispatch} = props const fn = useMemo(() => bindActionCreators({ increment, decrement }, dispatch), [dispatch]) // 如果想用 decrement 也是这样调用 fn.decrement(100) return ( <div className="App"> <div> val: {props.value} </div> <button onClick={() => { fn.increment(100) }}>plus </button> </div> ); } 源码解析 function bindActionCreator(actionCreator, dispatch) { return function () { // 执行 dispatch(actionCreator()) === dispatch({type:''}) return dispatch(actionCreator.apply(this, arguments)) } } function bindActionCreators(actionCreators, dispatch) { if (typeof actionCreators === 'function') { // 如果是函数直接执行 bindActionCreator return bindActionCreator(actionCreators, dispatch) } if (typeof actionCreators !== 'object' || actionCreators === null) { throw new Error(/*省略*/) } // 定义变量 const boundActionCreators = {} // 因为是对象 循环遍历, 但是 for in 效率太差 for (const key in actionCreators) { const actionCreator = actionCreators[key] // 过滤 if (typeof actionCreator === 'function') { // 和函数同样 执行 bindActionCreator 并且赋值到 boundActionCreators 中 boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) } } return boundActionCreators }

bindActionCreators 的源码相对简单一点, 理解起来相对也容易很多

总结

redux 中设计的很多地方都是很巧妙的,并且短小精悍, 值得大家作为首次源码阅读的选择

如果我讲的有什么问题, 还望不吝指教

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfsgs.html