✍️ 视角模拟: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 | 状态变更唯一入口,保证一致性与调试能力 |
| subscribe | UI 响应状态变化的桥梁 |
| reducer | 可组合、可测试的状态管理核心 |
| init dispatch | 初始化状态结构(类似默认构造器) |
Redux 不靠「黑魔法」,靠的是最基础、最纯粹的闭包与事件模型。这就是它如此稳定、长寿、易维护的根本原因。