9、最简 Redux 实现:从 0 构建可用的状态容器

49 阅读3分钟

✍️ 敲击开始

🎯 目标:用不到 100 行代码,构建你自己的 Redux

🧠 关键词:createStore、subscribe、dispatch、applyMiddleware、compose、闭包封装、洋葱模型


✅ 我们要实现的功能列表

一个最简 Redux 实现应具备以下能力:

功能是否实现描述
状态存储 getState()获取当前状态
状态变更 dispatch()派发 action,修改状态
状态监听 subscribe()订阅状态变化
初始化 action派发 @@INIT 初始化 state
中间件 applyMiddleware()支持注入增强 dispatch 的中间件
中间件链式组合 compose()多个中间件组合串联执行

✍️ 最简 Redux 实现(TypeScript 版本)

type Reducer<S, A> = (state: S, action: A) => S
type Listener = () => void
type Middleware<S, A> = (store: Store<S, A>) => (next: Dispatch<A>) => (action: A) => any
type Dispatch<A> = (action: A) => any

interface Store<S, A> {
  getState: () => S
  dispatch: Dispatch<A>
  subscribe: (listener: Listener) => () => void
}

export function createStore<S, A>(
  reducer: Reducer<S, A>,
  preloadedState: S,
  enhancer?: (createStore: typeof _createStore) => typeof createStore
): Store<S, A> {
  if (enhancer) {
    return enhancer(createStore)(reducer, preloadedState)
  }

  let currentState = preloadedState
  const listeners: Listener[] = []

  function getState() {
    return currentState
  }

  function subscribe(listener: Listener) {
    listeners.push(listener)
    return () => {
      const index = listeners.indexOf(listener)
      if (index >= 0) listeners.splice(index, 1)
    }
  }

  function dispatch(action: A) {
    currentState = reducer(currentState, action)
    listeners.forEach(listener => listener())
    return action
  }

  dispatch({ type: '@@redux/INIT' } as unknown as A)

  return { getState, dispatch, subscribe }
}

➕ 中间件增强机制:applyMiddleware + compose

export function applyMiddleware<S, A>(...middlewares: Middleware<S, A>[]) {
  return (createStore: typeof _createStore) =>
    (reducer: Reducer<S, A>, preloadedState: S) => {
      const store = createStore(reducer, preloadedState)
      let dispatch: Dispatch<A> = () => { throw new Error('Dispatching during setup') }

      const middlewareAPI = {
        getState: store.getState,
        dispatch: (action: A) => dispatch(action)
      }

      const chain = middlewares.map(mw => mw(middlewareAPI))
      dispatch = compose(...chain)(store.dispatch)

      return {
        ...store,
        dispatch
      }
    }
}

function compose<A>(...funcs: Function[]): (arg: A) => A {
  if (funcs.length === 0) return (arg: A) => arg
  if (funcs.length === 1) return funcs[0]
  return funcs.reduce((a, b) => (...args: any[]) => a(b(...args)))
}

🧪 使用方式

const logger = store => next => action => {
  console.log('prev state', store.getState())
  const result = next(action)
  console.log('next state', store.getState())
  return result
}

const reducer = (state = { count: 0 }, action) => {
  if (action.type === 'INC') return { count: state.count + 1 }
  return state
}

const store = createStore(reducer, { count: 0 }, applyMiddleware(logger))

store.subscribe(() => {
  console.log('订阅触发:', store.getState())
})

store.dispatch({ type: 'INC' })

输出:

prev state { count: 0 }
next state { count: 1 }
订阅触发: { count: 1 }

🧠 原理解读

功能技术手段说明
闭包封装状态currentState 隐藏于闭包,外部不可变
发布订阅模型listeners 列表手动维护
函数组合机制compose() 实现中间件洋葱模型
dispatch 劫持applyMiddleware 替换原始 dispatch

🧩 可扩展能力设计点

  1. ✅ 支持多个中间件(compose 组合链)

  2. ✅ 支持默认状态(preloadedState)

  3. ✅ 支持取消订阅(unsubscribe 函数)

  4. 🔜 可拓展:

    • replaceReducer() 动态热更新 reducer
    • combineReducers() 多模块 reducer 合并
    • devtoolsBridge() 接入 Redux DevTools

🧳 工程建议:手写 Redux 的用途

  • 帮助初学者理解 Redux 核心原理
  • 快速搭建轻量状态容器(适合浏览器插件、小项目、实验性场景)
  • 在构建自己的状态管理工具(如状态机、时间流架构)时,参考 Redux 的模式化思想

🔚 总结

你现在拥有了:

  • 一个支持订阅、更新、状态访问的最小 Redux;
  • 一个可组合、可插拔的中间件系统;
  • 你自己构建的 Redux 内核,从核心逻辑到扩展机制一手掌握。

这是理解框架的最好方式:重写它。


⏭️ 下一篇预告

最终篇即将到来:

第10篇:《Redux 可扩展设计:如何在极简 Redux 上构建完整状态框架?》 你将在第9篇基础上加入:

  • combineReducers
  • replaceReducer
  • DevTools 托管
  • 状态持久化
  • 模块热更新 让你的 Redux 成为工业级架构的内核之一。