Redux是从Flux这个编程思想的一种实现,或者说从Flux演变而来,同时还做了些封装和变换,让开发者更容易对前端应用状态进行管理和维护。由于Redux的成功,也逐渐演化出其他的一些类似框架,如mobx,vuex等等。
很多人喜欢说Redux接入之后,就是MC*框架了,我个人理解是,这个就是一个很好用的状态管理,和MVC或者MVVM等框架没有必然联系,思路也不完全一致,没必要非要定义出它是谁和它不是谁的结论出来,只要引入这个框架之后,我们的应用扩展性变好了,维护性,可测试性,等程序架构设计的指标变的更好了,就是合适当前项目的好框架。
今天我们主要谈一谈它与React的结合,Redux也成了React状态管理的御用框架,在目前(2020年)算是最主流的,当然React还可以与其他框架合作,如GraphQL,mobx等框架,并没有强制绑定。同时React项目也可以不与任何状态管理框架集成,但随着大型前端项目复杂度的增加,过多的业务逻辑,处理流程糅合在一起,就会出现职责不单一,交互困难,维护成本过高等问题,所以中大型项目还是需要一个 "专业" 的tool来帮忙。
Redux的核心流程是怎么样的呢?
1. dispatch( action) ==> reducers 处理得到新的state ==》store 去通知监听者响应变化。
本质来说,就是一种观察者模式,观察者(component)通过拉(pull)模式从store的全量state中选取出自己需要关注的子state作为props传递给展示组件进行渲染,它是一种单向数据流方式。
redux最核心的估计就是createStore()方法,简要记录几点
了解下方法的基本结构
//简易核心实现
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
}
};
// 这里初始化dispatch的原因是在这之前,state是为null的
//所以我需要传一个不存在的action去reducer里面,拿到最默认的那个defaultState,这个defaultState写在reducer的那个文件里面
dispatch({});
return { getState, dispatch, subscribe };
};
function(reducer, preloadedState, enhancer){ let currentReducer = reducers; let currentState = preloadedState; let currentListeners = []; let isDispatching = false; //这个全局变量主要用于dispatch action时,不允许多个同时action同时触发,强制同步。 // some codes to define core function. return { dispatch, getState, subscribe, replaceReducer } }
2. listeners 数组里面放的是什么?
其实源码分析发现,它都是function,当store中的action触发reducers得到新的state后,store通过forEach 遍历所有listener执行.
那这个function怎么通知到我们的component呢?
是在react-redux 核心方法 connect中 ,通过provider传递给容器组件的context---store,store.subscribe(func), 这个func会push到listeners这个数组中。那这个func是什么?实际上操作容器组件的state的方法,react 组件中,state变化,则会导致重新渲染,也就会导致被包装组件的重新渲染。
3. createStore 方法里面维护了几个闭包?
a. 一个是currentReducers,这个就可以让store支持热替换reducers,store.replaceReducer()。
b. currentState, 这个是store的单一唯一的全局数据对象,单一store,单一的state,通过getState获取。通过(prevState, action) => newState,对这个变量修改
c. listeners, 这个是数组,存放所有的观察者注入进来的方法,当state变化时,调用这些方法,这些方法会去修改component的state,从而触发组件树的更新。
4. 几个Redux源码片段
function dispatch(action) { 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 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 subscribe(listener) { 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 getState() { return currentState }