ByAI:Redux中间件的原理和ts简化实现

React 中间件(通常指 Redux 中间件)的核心作用是增强 dispatch 方法,使其能够处理异步操作或添加日志等附加功能


一、中间件原理

1. 核心目标

  • 扩展 dispatch 功能 :允许 dispatch 接收函数(如异步 Action)或其他非普通 Action 对象。
  • 保持单向数据流 :中间件在调用 next(action) 后仍需将控制权交还给 Redux 流程。

2. 中间件签名

typescript 复制代码
type MiddlewareAPI<S = any, A extends Action = Action> = {
  dispatch: Dispatch<A>; // 原始 dispatch 方法
  getState: () => S;     // 获取当前状态
};

type Middleware<S = any, A extends Action = Action> = (
  api: MiddlewareAPI<S, A>
) => (next: Dispatch<A>) => Dispatch<A>;
  • **MiddlewareAPI**:提供 dispatchgetState 的访问权限。
  • 中间件工厂函数 :接收 MiddlewareAPI,返回一个增强后的 dispatch 函数。

3. 中间件链式调用

多个中间件通过 ​柯里化​ 组合成一个"洋葱模型":

执行顺序:
Action → Middleware1 → Middleware2 → ... → 原始 dispatch → Reducer → 更新 State → 反向通知 Middleware


二、TypeScript 实现

1. 定义类型

typescript 复制代码
type Action = { type: string };
type Dispatch = (action: Action) => void;
type GetState = () => any;
type MiddlewareAPI = { dispatch: Dispatch; getState: GetState };
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch;
type Reducer<S> = (state: S, action: Action) => S;

2. 应用中间件(applyMiddleware)

typescript 复制代码
// applyMiddleware 函数实现
function applyMiddleware(...middlewares: Middleware[]): (createStore: typeof createStore) => typeof createStore {
  return (createStore) => (reducer, initialState) => {
    // 创建原始 store
    const store = createStore(reducer, initialState);
    
    // 创建中间件 API
    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action) => store.dispatch(action)
    };
    
    // 给每个中间件注入 middlewareAPI,得到新的 dispatch 函数
    const chain = middlewares.map(middleware => middleware(middlewareAPI));
    
    // 组合所有中间件的 dispatch 函数
    let enhancedDispatch = chain.reduceRight((next, middleware) => middleware(next), store.dispatch);
    
    // 返回一个新的 store 对象,替换原来的 dispatch
    return {
      ...store,
      dispatch: enhancedDispatch
    };
  };
}

3. 完整代码

ts 复制代码
// 定义类型
type Action = { type: string };
type Dispatch = (action: Action) => void;
type GetState = () => any;
type MiddlewareAPI = { dispatch: Dispatch; getState: GetState };
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch;
type Reducer<S> = (state: S, action: Action) => S;

// createStore 函数实现
function createStore<S>(
  reducer: Reducer<S>,
  initialState: S,
  enhancer?: (createStore: typeof createStore) => typeof createStore
): { dispatch: Dispatch; subscribe: (listener: () => void) => () => void; getState: GetState } {
  // 如果有 enhancer,则应用它
  if (enhancer) {
    return enhancer(createStore)(reducer, initialState);
  }

  let state = initialState;
  const listeners: (() => void)[] = [];

  // 获取当前状态
  const getState: GetState = () => state;

  // 分发 action
  const dispatch: Dispatch = (action) => {
    state = reducer(state, action);
    // 通知所有订阅者
    listeners.forEach(listener => listener());
  };

  // 订阅状态变化
  const subscribe = (listener: () => void) => {
    listeners.push(listener);
    // 返回取消订阅的函数
    return () => {
      const index = listeners.indexOf(listener);
      if (index !== -1) {
        listeners.splice(index, 1);
      }
    };
  };

  // 初始化状态
  dispatch({ type: '@@INIT' });

  return { dispatch, subscribe, getState };
}

// applyMiddleware 函数实现
function applyMiddleware(...middlewares: Middleware[]): (createStore: typeof createStore) => typeof createStore {
  return (createStore) => (reducer, initialState) => {
    // 创建原始 store
    const store = createStore(reducer, initialState);
    
    // 创建中间件 API
    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action) => store.dispatch(action)
    };
    
    // 给每个中间件注入 middlewareAPI,得到新的 dispatch 函数
    const chain = middlewares.map(middleware => middleware(middlewareAPI));
    
    // 组合所有中间件的 dispatch 函数
    let enhancedDispatch = chain.reduceRight((next, middleware) => middleware(next), store.dispatch);
    
    // 返回一个新的 store 对象,替换原来的 dispatch
    return {
      ...store,
      dispatch: enhancedDispatch
    };
  };
}

三、完整使用示例

1. 创建增强后的 Store

typescript 复制代码
// logger 中间件实现
const loggerMiddleware: Middleware = (api) => (next) => (action) => {
  console.log('dispatching', action);
  const result = next(action);
  console.log('next state', api.getState());
  return result;
};

// thunk 中间件实现
const thunkMiddleware: Middleware = (api) => (next) => (action) => {
  // 如果 action 是函数,则调用它,并传入 dispatch 和 getState
  if (typeof action === 'function') {
    return action(api.dispatch, api.getState);
  }
  // 否则,正常分发 action
  return next(action);
};

// 示例 reducer
function counterReducer(state: number = 0, action: Action): number {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

// 测试代码
function testRedux() {
  // 创建带有中间件的 store
  const store = applyMiddleware(thunkMiddleware, loggerMiddleware)(createStore)(counterReducer, 0);
  
  // 订阅状态变化
  const unsubscribe = store.subscribe(() => {
    console.log('state changed:', store.getState());
  });
  
  // 分发普通 action
  store.dispatch({ type: 'INCREMENT' });
  
  // 分发 thunk action
  store.dispatch((dispatch, getState) => {
    console.log('thunk action start, current state:', getState());
    dispatch({ type: 'INCREMENT' });
    dispatch({ type: 'INCREMENT' });
    console.log('thunk action end');
  });
  
  // 分发普通 action
  store.dispatch({ type: 'DECREMENT' });
  
  // 取消订阅
  unsubscribe();
}

// 运行测试
testRedux();

四、关键设计解析

  1. 中间件执行顺序
    applyMiddleware 从右到左组合中间件(类似函数组合 f(g(h(dispatch)))),但实际调用时从左到右执行(洋葱模型)。

  2. Thunk 中间件原理

    通过检查 action 是否为函数,支持异步操作:

    typescript 复制代码
    if (typeof action === 'function') {
      action(dispatch, getState); // 允许在函数内分发多个 Action
    }
  3. 类型安全

    • Dispatch 类型扩展为支持函数 Action。
    • 中间件工厂函数严格约束 MiddlewareAPInext 的类型。

五、与 React-Redux 的关联

React-Redux 的 connect 或 Hooks(如 useDispatch)内部会使用 Redux 的 dispatch,因此中间件对 React 组件透明。开发者只需关注:

  • 普通 Action:dispatch({ type: 'INCREMENT' })
  • 异步 Action:dispatch(async (dispatch) => { ... })

六、总结

  • 中间件本质 ​:通过包装 dispatch 方法,在 Action 到达 Reducer 前插入逻辑。

  • 典型中间件​:

    • redux-thunk:处理异步 Action(函数)。
    • redux-logger:记录日志。
    • redux-saga:基于 Generator 的复杂副作用管理(需更高级实现)。
相关推荐
拾光拾趣录6 分钟前
内存泄漏的“隐形杀手”
前端·性能优化
摸鱼仙人~31 分钟前
HttpServletRequest深度解析:Java Web开发的核心组件
java·开发语言·前端
索西引擎35 分钟前
【工程化】浅谈前端构建工具
前端·webpack·gulp·turbopack
ZzMemory39 分钟前
一文搞懂前端开发必备的导入导出方式
前端·面试·前端工程化
Stark_Tony40 分钟前
SystemUI开发
前端
愿天深海42 分钟前
Flutter 提取图像主色调 ColorScheme.fromImageProvider
android·前端·flutter
G等你下课1 小时前
你还在 import { Button } from './components'?
前端·react.js
已读不回1431 小时前
前端内存优化篇-防止长时间不操作内存累加(socket推送频繁项目非常有效)
前端
归于尽1 小时前
别再堆重复代码了!React 高阶组件带你优雅偷懒
前端
PineappleCoder1 小时前
React函数组件的"生活管家"——useEffect Hook详解
前端·react.js