Skip to content

redux

redux 是什么

  • redux 是 react 状态管理工具库,可以实现跨组件通信

redux 设计思想

TIP

redux 核心设计思想,利用发布、订阅者模式来实现

  • 1、在调用createStore时,接收二个参数reducerinitState,返回一个 store 实例
  • 2、内部会初始化 state、listeners 收集器,会向全局暴露出三个函数getStatesubscribedispatch
  • 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 是用来连接组件和仓库的,内部将订阅、解绑、视图更新统一的进行封装,简化用户的操作,由两个部分组成Providerconnect

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 };
    };
  };
}