3、Redux 核心架构源码解读(上)——createStore 是如何运作的?

92 阅读3分钟

✍️ 视角模拟:Redux 作者 Dan Abramov 的内心独白

🧠 主题:createStore 的设计底层逻辑

🔍 关键词:闭包、订阅发布、事件模型、状态快照、架构最小内核


🧬 我们为什么只用 40 行代码实现 Redux 内核?

当我们(Dan Abramov 和 Andrew Clark)决定创造 Redux 时,有一个目标非常清晰:

“最小可用的状态容器,只关心同步数据流的状态变更。”

我们拒绝一切魔法、拒绝隐藏副作用,只提供:

  • 状态读取(getState)
  • 状态更新(dispatch)
  • 订阅监听(subscribe)

🔧 先看源码:Redux 内核是如何构成的?

下面是 Redux 最早期版本 createStore 的核心实现(约 40 行):

function createStore(reducer, preloadedState) {
  let currentState = preloadedState
  let currentListeners = []

  function getState() {
    return currentState
  }

  function subscribe(listener) {
    currentListeners.push(listener)
    return () => {
      const index = currentListeners.indexOf(listener)
      currentListeners.splice(index, 1)
    }
  }

  function dispatch(action) {
    currentState = reducer(currentState, action)
    currentListeners.forEach(listener => listener())
  }

  // 初始化 state
  dispatch({ type: '@@redux/INIT' })

  return { getState, dispatch, subscribe }
}

🧠 深度剖析每一个函数的设计思维

1️⃣ getState():只读数据,不准改

function getState() {
  return currentState
}

设计思路:

  • 绝不提供 setState
  • 所有外部只能 dispatch
  • 核心思想:不让“谁都能修改状态”成为潜在地雷。

2️⃣ subscribe(listener):注册监听器

function subscribe(listener) {
  currentListeners.push(listener)
  return () => { /* 取消订阅逻辑 */ }
}

架构背后:

  • 这是一个事件模型;
  • 我们采用 观察者模式,但不依赖外部事件库;
  • Redux 自带的订阅,是为UI 层(比如 React-Redux)服务的;
  • 返回取消函数(unsubscribe),是参考 DOM 的 addEventListener

3️⃣ dispatch(action):唯一的状态变更入口

function dispatch(action) {
  currentState = reducer(currentState, action)
  currentListeners.forEach(listener => listener())
}

为什么强制通过 dispatch

因为我们想构建一个“状态快照流水线”:

  • 每次调用 dispatch,都有明确的前置状态与后置状态;
  • 如果你把这些状态保存下来,就可以做时间旅行(Time Travel Debugging);
  • 这也是 Redux-DevTools 的实现原理。

4️⃣ reducer 是什么角色?

currentState = reducer(currentState, action)

这是整个 Redux 的“大脑”:

  • 接收 state + action;
  • 返回新的 state;
  • 必须是纯函数;
  • 它的本质是:状态转移矩阵(State Transition Graph)

这就是为什么我们不允许在 reducer 里搞异步、不允许副作用——

❗ Redux 并不是“只为你服务的状态工具”,它也是一个“调试友好系统”。 所以我们用“暴力纯函数”强迫你把状态变更流程写清楚。


🧪 示例:还原 Redux 的最简内核并运行

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

const store = createStore(reducer)

store.subscribe(() => {
  console.log('状态变化:', store.getState())
})

store.dispatch({ type: 'INC' }) // { count: 1 }
store.dispatch({ type: 'INC' }) // { count: 2 }

🧩 为什么我们不一开始就支持异步?

这是 Redux 最常被诟病的点。但我想告诉你:

Redux 从不处理异步。它是同步状态的架构。异步属于你的架构边界,属于 middleware。

正因如此,我们才设计了 applyMiddleware(下一篇会讲)——让你用 redux-thunk、redux-saga 等方式做副作用管理。


🪢 总结:“极简”才是 Redux 的杀手锏

功能背后动机
getState避免重复请求与全局依赖,保持透明性
dispatch状态变更唯一入口,保证一致性与调试能力
subscribeUI 响应状态变化的桥梁
reducer可组合、可测试的状态管理核心
init dispatch初始化状态结构(类似默认构造器)

Redux 不靠「黑魔法」,靠的是最基础、最纯粹的闭包与事件模型。这就是它如此稳定、长寿、易维护的根本原因。