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 的复杂副作用管理(需更高级实现)。
相关推荐
LuckySusu1 分钟前
【CSS篇】什么是 Margin 重叠问题?如何解决?
前端·css
一依不舍1 分钟前
百度文心大模型 4.5 系列开源:从技术突破到全球生态的中国力量
前端
LaoZhangAI3 分钟前
Claude 4 vs Gemini 2.5 Pro:2025年顶级AI模型权威对比分析
前端·后端
Dream耀3 分钟前
Cookie:Web身份认证的基石
前端·javascript·http
LuckySusu4 分钟前
【CSS篇】元素的层叠顺序(Stacking Order)详解
前端·css
come112345 分钟前
npm 命令入门指南(前端小白版)
前端·npm·node.js
墨菲安全6 分钟前
NPM组件 alan-baileys 等窃取主机敏感信息
前端·npm·node.js·npm组件·恶意包·主机信息窃取
我在北京coding6 分钟前
npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree
前端·npm·node.js
拾光拾趣录7 分钟前
CSS高级技巧与实用伪类
前端·css
whale fall8 分钟前
npm代理设置 + npm配置镜像源
前端·npm·node.js