redux简介
redux 是一个三方通用的状态管理库,它采用单一集中化的state和发布订阅者模式,通过dispatch action事件管理状态。
核心概念
store:状态容器,用于状态的存储和管理。
dispatch:事件派发函数,触发reducer更新状态
action:更新事件,通常是一个带有type属性的对象
基本工作流程
- 创建状态管理仓库:createState 接收reducer、preloadState和 enhancer,返回状态仓库对象(store)。
- reducer是一个函数,接收当前state和action,返回新的state。新的state需要是一个新的对象,state应遵循不可变更新原则。
- preloadState 是一个对象,用于初始化状态。通常用于状态持久化等操作
- enhancer 是一个函数,用于增强状态管理。可以通过Redux提供的applyMiddleware增强器,也可以通过第三方提供的增强器增强store的能力
- store 是一个对象,向外提供状态仓库访问(getState)、更新(dispatch)和订阅(subscribe)等方法
- 使用状态:通过store对象上的getState方法访问state。可以将取值器传入getState,精确的获取状态。
- 更新状态:通过store对象上的dispatch方法派发更新,dispatch接收action,调用reducer并将action传入。
- 订阅更新:通过store对象上的subscribe方法订阅更新,当state发生变化时(Object.is判断),通知订阅者。
高级应用
combineReducers:在redux的实际使用中,通过单个reducer管理状态的更新逻辑会让代码量变得非常的庞大和难以维护。我们可以创建多个reducer,每个reducer负责单个模块的更新逻辑。通过 combineReducers 辅助函数组合这些reducer。combineReducers 接收reducers对象,返回组合后的reducer,并在state上添加reducers的key,指向reducer返回的state。
-
Reducer的拆分和组合
phpfunction countReducer(state=preloadState, action) { switch (action.type) { case 'INCREMENT': return { ...state, count: state.count + 1 }; case 'DECREMENT': return { ...state, count: state.count - 1 }; default: return state; } } function userReducer(state=userInfo , action) { switch (action.type) { case 'SET_USER': return { ...state, user: action.user}; default: return state; } } const preloadState = { count: 0 }; const userInfo = { user: '' }; const store = createStore(combineReducers({ count: countReducer, user: userReducer, }));
enhancer:store功能增强。applyMiddleware是redux唯一内置的store增强器。
-
增强器的实现原理和基本使用如下
javascript//创建增强器,增强器接收createStore,返回新的createState //(nextCreateStore) => StoreCreator function autoEnhancer(next) { return (reducer, preloadState) => { console.log(next) const store = next(reducer, preloadState); return { ...store, consoleMsg: (msg: string) => msg, }; } } //创建Store createStore(reducer, proloadState, enhancer) //createStore的实现大致如下 function createStore(reducer, preloadState, enhancer) { //如果有增强器,就用增强器创建store if (enhancer) { return enhancer(createStore)(reducer, preloadState); } //如果没有增强器,就用默认的createStore创建store const state = reducer(preloadState, { type: '@@redux/INIT' }); return { dispatch: (action) => { state = reducer(state, action); }, getState: () => state, } }
通过上面增强器的基本原理,就可以对原store添加额外的能力,对store增强。
-
多增强器的使用。Redux提供了compose函数用于多增强器场景代码组织,如下:
javascript//创建增强器 function autoEnhancer(next) { return (reducer, preloadState) => { console.log(next) const store = next(reducer, preloadState); return { ...store, consoleMsg: (msg: string) => msg, }; } } function autoEnhancer2(next) { return (reducer, preloadState) => { const store = next(reducer, preloadState); return { ...store, consoleMsg2: (msg: string) => (`consoleMsg2: ${msg}`), }; } } //创建store。compose会将所有的增强器从右往左调用,最终组合成为一个增强器返回 const store = createStore(countReducer, preloadState, compose(autoEnhancer, autoEnhancer2)); //compose的内部核心原理 function compose(...enhancers) { //传给第一个增强器的createStore函数传递给最后一个增强器,将下一个增强器返回的结果作为参数传递给上一个增强器。最终返回一个增强器 return enhancers.reduce((prev, next) => (...args) => next(prev(...args))); }
-
applyMiddleware API的作用及原理。applyMiddleware的作用是对store的dispatch增强,允许在dispatch在到达reducer之前,做一些其他的任务处理,其基本实现如下:
javascriptfunction applyMiddleware(...middlewares){ return createStore => (reducer, preloadedState) => { const store = createStore(reducer, preloadedState); let dispatch: Dispatch = () => { throw new Error('Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.'); }; const middlewareAPI: MiddlewareAPI = { getState: store.getState, dispatch: (action, ...args) => dispatch(action, ...args) }; const chain = middlewares.map(middleware => middleware(middlewareAPI)); dispatch = compose<typeof dispatch>(...chain)(store.dispatch); return { ...store, dispatch }; }; }
结合redux middleware的使用,一步步剖析其执行过程,如下:
javascript//创建middleware const logMiddleware = function({ getState, dispatch }) { return next => action => { console.log("console"); const result = next(action); return result; } } const alertMiddleware = function({ getState, dispatch }) { return next => action => { console.log("alert"); const result = next(action); return result; } } //使用中间件 const store = createStore(countReducer, preloadState, applyMiddleware(logMiddleware, alertMiddleware)); //applyMiddleware的本质是一种store增强,所以applyMiddleware遵循增强器的声明规则,对于上述applyMiddleware中增强器的执行过程不做剖析。 //1、创建中间件链 const chain = middlewares.map(middleware => middleware(middlewareAPI)); //chain的结构是这样的 [ next=> action => { console.log("console"); const result = next(action); return result; }, next=> action => { console.log("alert"); const result = next(action); return result; }, ] //2、组合中间件链 let dispatch = compose<typeof dispatch>(...chain)(store.dispatch); //它等同于下面的代码 let dispatch = chain.reducer((prev, next) => (...args) => prev(next(...args)))(store.dispatch); //重写后的dispatch函数如下 action => { console.log("console"); const result = action => { console.log("alert"); const result = store.dispatch(action); return result; }; return result; }
中间件:对dispatch的能力增强。在上文【applyMiddleware API的作用及原理】中其实已经梳理了中间件的定义、挂载和整个工作流程的原理。可以看出,增强器和中间件是不同的:首先是在功能上面的区别,增强器是对store能力的扩展 ,而中间件是在dispatch到reducer过程中添加新的能力。导致在签名上也存在区别,增强器接收createStore,返回新的createStore,增强器通过compose组合成为一个增强器后提供给createStore;中间件则遵循({getStore, dispatch})=>next=>action => result函数签名。中间件需要通过redux提供的唯一增强器applyMiddleware注册到store,在applyMiddleware内部会将多个中间件组合成为一个dispatch。