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 的复杂副作用管理(需更高级实现)。
相关推荐
小小小小宇13 分钟前
前端按需引入总结
前端
小小小小宇30 分钟前
React 的 DOM diff笔记
前端
小小小小宇37 分钟前
react和vue DOM diff 简单对比
前端
我在北京coding39 分钟前
6套bootstrap后台管理界面源码
前端·bootstrap·html
Carlos_sam43 分钟前
Opnelayers:封装Popup
前端·javascript
前端小白从0开始1 小时前
Vue3项目实现WPS文件预览和内容回填功能
前端·javascript·vue.js·html5·wps·文档回填·文档在线预览
難釋懷2 小时前
Vue解决开发环境 Ajax 跨域问题
前端·vue.js·ajax
特立独行的猫a2 小时前
Nuxt.js 中的路由配置详解
开发语言·前端·javascript·路由·nuxt·nuxtjs
咸虾米2 小时前
在uniCloud云对象中定义dbJQL的便捷方法
前端·javascript