手写一个redux中间件

67 阅读2分钟

以下是一个手写的 Redux 中间件示例及其实现原理说明。我们以创建一个日志中间件为例,演示如何编写中间件:

完整代码实现

// 手写日志中间件
const loggerMiddleware = (store) => (next) => (action) => {
  // 1. 记录触发前的状态
  console.log('dispatching action:', action);
  console.log('current state:', store.getState());

  // 2. 将 action 传递给下一个中间件或 reducer
  const result = next(action);

  // 3. 记录处理后的新状态
  console.log('next state:', store.getState());

  // 4. 返回处理结果 (通常是 action 本身)
  return result;
};

// 使用示例
import { createStore, applyMiddleware } from 'redux';

const store = createStore(
  rootReducer,
  applyMiddleware(loggerMiddleware)
);

中间件结构解析

Redux 中间件采用三层嵌套函数结构:

const middleware = (store) => (next) => (action) => {
  // 中间件逻辑
}
  1. 外层函数 (store)
    接收包含 dispatchgetState 方法的 store 对象

  2. 中层函数 (next)
    接收链中下一个中间件的 dispatch 方法
    (如果是最后一个中间件,则 next 指向原始 store.dispatch

  3. 内层函数 (action)
    处理 action 的逻辑


高级中间件示例:异步处理

实现类似 redux-thunk 的异步处理能力:

const thunkMiddleware = ({ dispatch, getState }) => (next) => (action) => {
  // 如果 action 是函数,执行它并传入 dispatch/getState
  if (typeof action === 'function') {
    return action(dispatch, getState);
  }
  
  // 否则直接传递 action
  return next(action);
};

// 使用方式: 
dispatch((dispatch) => {
  setTimeout(() => {
    dispatch({ type: 'ASYNC_ACTION' })
  }, 1000)
})

核心实现要点

  1. 中间件链式调用
    每个中间件通过 next() 将 action 传递给下一个中间件

  2. 两种 dispatch 区别

    • next(action):传递给后续中间件
    • store.dispatch(action):重新走完整中间件链
  3. 状态获取时机

    • store.getState()next() 前获取当前状态
    • store.getState()next() 后获取新状态

中间件执行流程图

原始 dispatch
    ↓
中间件1 (处理 action)
    ↓ next()
中间件2 (处理 action)
    ↓ next()
...
    ↓ 
原始 reducer 处理

通过这种机制,中间件可以:

  • 修改/拦截 action
  • 添加异步逻辑
  • 记录状态变化
  • 实现撤销重做等高级功能