✍️ 敲击开始
🎯 目标:用不到 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 |
🧩 可扩展能力设计点
-
✅ 支持多个中间件(compose 组合链)
-
✅ 支持默认状态(preloadedState)
-
✅ 支持取消订阅(unsubscribe 函数)
-
🔜 可拓展:
replaceReducer()动态热更新 reducercombineReducers()多模块 reducer 合并devtoolsBridge()接入 Redux DevTools
🧳 工程建议:手写 Redux 的用途
- 帮助初学者理解 Redux 核心原理
- 快速搭建轻量状态容器(适合浏览器插件、小项目、实验性场景)
- 在构建自己的状态管理工具(如状态机、时间流架构)时,参考 Redux 的模式化思想
🔚 总结
你现在拥有了:
- 一个支持订阅、更新、状态访问的最小 Redux;
- 一个可组合、可插拔的中间件系统;
- 你自己构建的 Redux 内核,从核心逻辑到扩展机制一手掌握。
这是理解框架的最好方式:重写它。
⏭️ 下一篇预告
最终篇即将到来:
第10篇:《Redux 可扩展设计:如何在极简 Redux 上构建完整状态框架?》 你将在第9篇基础上加入:
- combineReducers
- replaceReducer
- DevTools 托管
- 状态持久化
- 模块热更新 让你的 Redux 成为工业级架构的内核之一。