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 的复杂副作用管理(需更高级实现)。
相关推荐
开开心心就好1 小时前
批量提取PDF中的图片,直接导出原图
前端·javascript·支持向量机·智能手机·pdf·html·启发式算法
Setsuna_F_Seiei3 小时前
前端转型 Agent 开发 05 之 Agent Hooks 与 Checkpointer(让 Agent 从全自动转变人为可掌控)
前端·agent·ai编程
百万蹄蹄向前冲5 小时前
风扇转了一晚上MVP专家团翻车事故
前端·人工智能
默_笙5 小时前
🏛 给 AI 配一间办公室:Harness Engineering 六大模块与它的实现
前端·javascript
linux_cfan6 小时前
videojs v10 源代码系列解读:14 · 谓词守卫:在运行时安全地调用能力
前端·javascript·音视频
liangshanbo12157 小时前
Redux 的中间件(Middleware)的工作机制
中间件·react·redux
kyriewen7 小时前
我扒了 10,221 条 JD:腾讯技术岗 75% 在要 AI
前端·人工智能·ai编程
郑州光合科技余经理7 小时前
同城外卖小程序开发:下单成功后,后台导出能不能对上用户端状态
开发语言·前端·git·后端·uni-app·php·ai编程
IT_陈寒8 小时前
Vue的响应式让我熬到凌晨三点,原来漏了这个小细节
前端·人工智能·后端
Blanche15008 小时前
利用 RAG 为答疑机器人扩展知识范围
前端