Appearance
redux
redux 是什么
- redux 是 react 状态管理工具库,可以实现跨组件通信
redux 设计思想
TIP
redux 核心设计思想,利用发布、订阅者模式来实现
- 1、在调用
createStore
时,接收二个参数reducer
、initState
,返回一个 store 实例 - 2、内部会初始化 state、listeners 收集器,会向全局暴露出三个函数
getState
、subscribe
、dispatch
- 3、getState:其实是方便外部获取最新的 state
- 4、subscribe:是一个订阅器,将订阅的数据存储在 listeners 收集器中,返回一个取消订阅的回调
- 5、dispatch:是一个派发器,目的就是执行
reducer
获取最新的 state,同时会执行所有的订阅器
js
export default function createStore(reducer, initState) {
let state = initState;
// 收集器
const listeners = [];
// 获取状态
const getState = () => {
return state;
};
/**
*
* @param {*} listener 订阅的函数
* @returns 取消订阅的函数
*/
const subscribe = (listener) => {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
};
/**
*
* @param {*} action action提交计算新的状态
*/
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach((listener) => listener());
};
dispatch({ type: "@@REDUX/INIT" });
return {
getState,
subscribe,
dispatch,
};
}
combineReducers
默认情况下,我们只有一 Reducer,如果项目比较庞大,所有的数据全部交个一个 Reducer 处理比较融冗余,
combineReducers
的目的就是将多个模块的 Reducer 进行合并成一个大的 Reducers,集中派发缺陷每次触发 dispatch,所有 reducer 都会执行一遍
js
/**
* 合并多个reducers
* @param {*} reducers
*/
export default function combineReducers(reducers) {
/**
* createStore执行dispatch触发
* @param {*} state 老的state状态
* @param {*} action action动作
*/
return function combination(state = {}, action) {
// 总的state
let nextState = {};
// TODO:缺陷每次触发dispatch,所有reducer都会执行一遍
for (const key in reducers) {
const preState = state[key]; // 老的state状态
nextState[key] = reducers[key](preState, action);
}
return nextState;
};
}
react-redux
- react-redux 是用来连接组件和仓库的,内部将订阅、解绑、视图更新统一的进行封装,简化用户的操作,由两个部分组成
Provider
、connect
Provider
- Provider 组件其实是
createContext
创建出来的 - 目的就是把 store 实例存储在 Context 上下文对象中
js
import { createContext } from "react";
export const ReactReduxContext = createContext( null );
export default ReactReduxContext;
/**
* 利用Context给子孙组件传递store实例
* @param {*} props store实例
* @returns
*/
export default function Provider ( props ) {
return (
<ReactReduxContext.Provider value={{ store: props.store }}>
{props.children}
</ReactReduxContext.Provider>
)
}
connect
- connect 是连接组件和仓库的核心
- connect 是一个
高阶组件
,内部会从 Context 上下文解析出 store 实例 - 内部会自动进行订阅,当触发 Dispatch 时,会通知订阅器,获取最新的 state,触发更新视图
- 最后会将 props、state 传递给原始的组件并且返回组件
js
import { Component } from "react";
import ReactReduxContext from "./ReactReduxContext";
/**
* 连接组件和仓库
* @param {*} mapStateToProps
* @param {*} mapDispatchToProps
* @returns
*/
export default function connect(mapStateToProps, mapDispatchToProps) {
return (OldComponent) => {
return class extends Component {
static contextType = ReactReduxContext; // 注入store实例
constructor(props, context) {
super(props);
// 解析store实例
let {
store: { getState, subscribe, dispatch },
} = context;
this.state = mapStateToProps(getState());
// 订阅,dispatch执行会触发订阅器,触发更新
this.unsubscribe = subscribe(() => {
this.setState(mapStateToProps(getState()));
});
let dispatchProps;
if (typeof mapDispatchToProps === "function") {
// 执行注入dispatch
dispatchProps = mapDispatchToProps(dispatch);
} else {
dispatchProps = {};
// 将action动作,转换成dispatch能触发的动作
for (const key in mapDispatchToProps) {
dispatchProps[key] = () => dispatch(mapDispatchToProps[key]());
}
}
this.dispatchProps = dispatchProps;
}
// 组件销毁时取消订阅
componentWillUnmount() {
this.unsubscribe();
}
render() {
return (
<OldComponent
{...this.props}
{...this.state}
{...this.dispatchProps}
></OldComponent>
);
}
};
};
}
applyMiddleware 中间件处理
TIP
中间件处理函数,方便开发人员根据自己的需求定制自己的插件
- applyMiddleware 是一个三层闭包函数,
- 第一层接收中间件、
- 第二层接收 createStore、
- 最后一层接收总的 reducer 和 初始的 initState
- 内部会创建 Store 实例,创建 middlewareAPI 封存在中间件内部
- 调用每一个中间件,形成调用栈,最后返回 store 实例,和加强后的 dispatch
js
// BUG:如果在中间件直接调用第一层的dispatch,会造成死循环
export default function logger({ getState, dispatch }) {
return (nextDispatch) => {
return (action) => {
console.log("更新前", getState());
nextDispatch(action);
console.log("更新后", getState());
};
};
}
js
import compose from "./compose";
/**
*
* @param {...any} middlewares 中间件
*/
export default function applyMiddleware(...middlewares) {
return (createStore) => {
return (reducer, initState) => {
let dispatch;
// 创建Store实例
const store = createStore(reducer, initState);
// 封存中间件API
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action), // 加强后的dispatch
};
// 揭开中间第一层(封存原始的store)
// BUG:如果在中间件直接调用第一层的dispatch,会造成死循环
const chain = middlewares.map((middleware) => middleware(middlewareAPI));
// 增强后的dispatch(揭开中间第二层)
dispatch = compose(...chain)(store.dispatch);
// 第三层用户去触发
return { ...store, dispatch };
};
};
}