react和redux生态源码解析
07 April 2019

redux是我阅读知名库源码的迈开的第一步,2年前结合函数式编程思想也总结过redux源码阅读笔记。但是当时没有将整个体系串起来弄清楚。现在再读,redux简洁明了的源码真是感人,整个流程特别容易理解了。

redux

核心能力:提供数据存储,分发、变更的机制。意在管控数据流的变更,让一切变更可感知,配合单向数据流。

包含createStore、applyMiddleware、bindActionCreator、combineReducer四个组成部分,也是对外提供的api。其中bindActionCreatorcombineReducer为辅助工具。

createStore

核心的createStore提供获取state的getState方法和变更数据的dispatch方法,applyMiddleware提供的中间件组装机制,能让中间件在数据变更前进行对应处理,这个阶段可以更改state,中间件可以封装出更有能力的dispatch。

  • dispatch的能力是调用reducer函数传入oldStateaction获得最新的state, 并且调用store.subscribe注册的listeners
  • getState则直接返回createStore里的局部变量currentState

如果有enhancer如调用中间件的applyMiddleware,则将当前函数作为参数传给applyMiddleware处理。否则,构造出getState\dispatch返回

applyMiddleware

真正调用createStore获得dispatch和getState,给每个中间件注入这2个接口

dispatch的封装

dispatch: function dispatch(action){
  return _dispatch(action);
}

这种写法是为了保证是middleware第一层获取到的dispatch是最初来自createStore的的dispatch,而后面_dispatch=compose.apply(undefined, chain)(store.dispatch)的dispatch则是被中间件包装处理的含有各种功能的dispatch。而这一步正是调用下面redux thunk中createThunkMiddleware封装的dispatch的地方:

可以看出next就是compose组合的各个中间件函数。

redux中间件

中间件可以接受dispatch和getState函数,且必须返回action, 格式:

function middleware(){
    return ({dispatch, getState}) => next => action => {
        //封装action
        return action
    }
}

这个函数式的经典风格其实挺绕的,第一层是在applyMiddleware里调用middleware(middlewareAPI)消费,第二层next是applyMiddleware的compose获取封装的dispatch时消费,第三层action是最终action触发dipatch调用时消费。

applyMiddleware的调用时机

createStore的调用有2种格式:

无论哪一种,最终经过内部逻辑后都是一样的后续流程。最后一个参数就是enhancer,最终会调用enhancer(createStore)(reducer, preloadedState)

所以applyMiddleware里的第一层return (createStore) => {}在这里调用,第二层也紧接着被调用。

可以看出,applyMiddleware作用是获取各个中间件封装后的最终dispatch并和原始store一起返回。

bindActionCreator

调用姿势:

connect(
  (state) => {
    return {
      compName :state.compNameState,
    }
  },
  (dispatch) => {
    return {
      actions: bindActionCreators(compNameAction, dispatch)
    }
  }
)(comp, compNameAction);

这里connect来源于react-redux, bindActionCreators来源于redux。

将action函数用dispatch封装一层,视图层就不需要再传入dispatch了。bindActionCreators中的dispatch来源于视图层<provider>中注入的store里的dispatch

redux-thunk

为了解决频繁出现的异步action的需求,redux-thunk也是必不可少的库

当有异步等需要处理时,我们写aciton时格式是:

function actionFn(){
    return (dispatch, getstate) => {
        return dispatch(otherFn)
    }
}

这样就能将redux-thunk注册的dispatchgetState给内部层层调用,直到最终dipatch获得的是简单的对象型action,走next(action)。这里的next如果有中间件,会进入中间件里。

中间件里的next指向下一个中间件:store => next => action => { //handler }

react-redux

可以看到redux虽然总是被用在react的生态体系内,但是其实他们没有绑定关系,redux完全是个独立的管理数据的库。要和react配套使用,要react-redux来作为连接桥梁。

理解了这个库的作用才理解了react和redux那一套是怎么闭环的。

它的实现是将redux store里记录的state 注入到组件里,通过提供Provider和高阶组件Connect来连接。

Provider

Provider仅仅是获取到createStore创建出的store对象供自己调用,再传递到内部组件,实现让开发者写的组件能通过props获取到redux管理的数据。

Connect:

通过调用store.subcribe来监听state的变更,在state变更时对自己的组件setState,从而达到更新视图获取组件的state 还会有mapStateToPropsmapDispatchToProps来分发只记录被过滤的reducer和action作为当前组件的state 其他一坨判断都是更新之类的把控

参考文档

Redux入坑进阶-源码解析