为什么是 Redux
我们知道 Redux 是一款状态管理类库,首先要明确为什么需要它?
对于跨层级的组件通信,React 中开始是使用 Context。但 Context 属于简单状态管理类库。显著特征是把要传递的数据放在组件最顶层,然后往下传递。对大量复杂的状态数据,传递下去的数据状态难以做到准确的管理,有时会造成重复渲染,在 React 中属于高级 API ,需要谨慎使用。
所以引出 Redux,单独的状态管理库,强调单向数据流,更改状态的方法提前声明,且只能通过 dispatch 触发。和 React 组件本身做解耦。
Redux 使用五步曲
createStore创建store,入参为reducerreducer初始化、定义好修改要状态的函数store.getState()获取状态store.dispatch({type: '', payload:})派发更新store.subscribe订阅状态变更
实现 Redux 及其类库
关键节点按照注释中的顺序阅读,应该不会迷路。
/**
* 第二个参数就是 applyMiddleware 的执行结果
* 是一些中间件,核心用来加强 dispatch,比如支持 异步
* @param {*} reducer
* @param {*} enhancer
* @returns store
*/
function createStore(reducer, enhancer) {
let curState;
let subscribeList = [];
//2. 传递进来的 enhancer 是一个函数,为啥呢,因为我们要对原来的 dispatch 做加强
// 首先要得到原来的 dispatch,需要先传递 createStore
//3. 传递完 createStore 之后,函数内部会注入中间件,最后传入 reducer 生成包含加强
// 后的 dispatch。这里有相当于是一个高阶函数,需要仔细看。
if(enhancer) {
enhancer(createStore)(reducer)
}
function getState() {
return curState;
}
function dispatch({type, payload}) {
curState = reducer({type, payload});
subscribeList.map(listener => listener());
}
function subscribe(listener) {
subscribeList.push(listener)
}
// 第一次初始化 state 的值
dispatch({type: '@init'});
return {
getState,
dispatch,
subscribe,
}
}
/**
* @param {*} middlewares
* @returns store
* 使用方式
* 0. let store = createStore(golbalReducer, applyMiddleware(logger, thunk));
*
* 1. 传给 createStore 的是 applyMiddleware 的执行结果
*/
function applyMiddleware(...middlewares){
return (createStore) => (reducer) => {
// 4. 传入 reducer 生成新的 store
const store = createStore(reducer);
// 5. 处理中间件
const injectPrams = {
getState: store.getState,
dispatch: store.dispatch
}
// 得到的 middlewaresFn 是传入了 middlewaresFn 的回调函数:
// action => {
// console.log('some logger');
// return dispatch(action)
// }
const middlewaresFn = middlewares.map(fn => fn(injectPrams));
// 使用 compose 将 middlewaresFn 聚合起来,传入 dispatch 得到新的 dispatch
// 类似 const dispatch = logger(thunk(dispatch));
// ! 把真正的dispatch包在最里面 !这里挺绕的要仔细看 !!!
// 第一次执行 thunk 返回一个回调函数
// 第二次执行 logger 也返回一个回调函数,并把第一次返回的回调函数当作参数传入。
// 当真正执行第二次回调的时候,会把第一次传进来的参数在末尾执行
// 当外部调用最后经过包装的dispatch 时,才真正开始执行回调函数
const dispatch = compose(middlewaresFn)(store.dispatch);
return {
...store,
dispatch,
}
}
}
/**
* 0 处传入的logger中间件长这样
*/
function logger(dispatch) {
return action => {
console.log('some logger');
return dispatch(action)
}
}
/**
* 0 出传入的thunk中间件长这样
*/
function thunk(dispatch) {
return action => {
if(typeof action === 'function') {
return action(dispatch);
}else{
return dispatch(action);
}
}
}
function compose(...fns) {
return fns.reduce((prev, next)=>(...args)=> {prev(next(...args))});
}
export {
createStore,
applyMiddleware
}
redux、react-redux、redux-saga、redux-thunk 之间的区别联系
应该很清晰了,redux-saga、redux-thunk 是 redux 的中间件,用来加强原本的 dispatch。react-redux 是专门适配 react 的,核心是加了层中间函数,方便书写和管理,后续再写 O_o。
「 一枚前端学习小透明,努力学习前端知识,同时分享自己对生活的一些思考,欢迎一起讨论交流。如果我的文章对你有帮助,请点个赞,会非常感恩你的鼓励。完」