✍️ 技术解析 + Redux 作者角度
📚 底层核心文件:
connectAdvanced.ts、Subscription.ts、ReactReduxContext.tsx🎯 目标:你将彻底明白
connect是如何“优雅注入状态 + 高效更新组件”的
✅ 第一步:connect ≠ connectAdvanced,后者才是真核
在 react-redux 中,connect 只是个“糖”:
export function connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
options
) {
return connectAdvanced(selectorFactory, options)
}
它调用的是底层函数:
connectAdvanced(selectorFactory, options)
其中 selectorFactory 是生成 props 的逻辑工厂,而 connectAdvanced 则管理:
- store 注入
- props 合成
- state 对比
- context 绑定
- 订阅更新
🧠 第二步:connectAdvanced 源码结构全图
function connectAdvanced(selectorFactory, options) {
return function wrapWithConnect(WrappedComponent) {
function ConnectFunction(props) {
const contextValue = useContext(ReactReduxContext)
const store = contextValue.store
const subscription = useMemo(() => new Subscription(store), [store])
const childPropsSelector = useMemo(() => selectorFactory(store.dispatch, options), [store])
const [childProps, forceUpdate] = useReducer(c => c + 1, 0)
useLayoutEffect(() => {
subscription.subscribe(() => {
const newProps = childPropsSelector(store.getState(), props)
if (!shallowEqual(newProps, childProps)) {
forceUpdate()
}
})
return () => subscription.unsubscribe()
}, [store])
const mergedProps = { ...props, ...childProps }
return <WrappedComponent {...mergedProps} />
}
return ConnectFunction
}
}
关键结构说明:
| 名称 | 作用说明 |
|---|---|
ReactReduxContext | 提供全局 Redux store 引用 |
Subscription | 组件级订阅封装(隔离更新链) |
selectorFactory | 用于生成 mapStateToProps + mapDispatchToProps + mergeProps |
useLayoutEffect | 保证同步订阅响应,避免跳帧 |
useReducer + forceUpdate | 触发组件重渲染的技巧 |
🔄 第三步:为什么不用 useState,而是 useReducer + forceUpdate?
因为我们不关心“某个新状态”,而只想「强制组件 render 一次」。
const [, forceUpdate] = useReducer(c => c + 1, 0)
等价于:
function update() {
renderCount += 1
rerender()
}
这是目前 React Hook 中触发重渲染的最佳方式之一,避免污染状态结构。
🧩 第四步:Subscription 是如何隔离更新链的?
源码文件:Subscription.ts
class Subscription {
constructor(store, parentSub) {
this.store = store
this.parentSub = parentSub
this.listeners = []
}
subscribe(listener) {
this.listeners.push(listener)
return () => this.unsubscribe(listener)
}
notify() {
for (const l of this.listeners) {
l()
}
}
}
Redux 的订阅不是在全局 store 上注册的,而是每个 connect 创建一个 独立的 Subscription 实例,挂载在组件自身上。
这有什么好处?
- 🚀 只更新自己;
- 🧩 支持嵌套组件
connect(子组件订阅不会被父组件遮挡); - 💡 组件卸载自动解除订阅。
🧪 第五步:性能优化全在 selectorFactory + shallowEqual
selectorFactory 的核心返回:
(state, ownProps) => mergedProps
它是这样组合的:
const propsFromState = mapStateToProps(state, ownProps)
const propsFromDispatch = mapDispatchToProps(dispatch, ownProps)
const mergedProps = mergeProps(propsFromState, propsFromDispatch, ownProps)
然后在每次 state 更新后:
const newProps = childPropsSelector(store.getState(), ownProps)
if (!shallowEqual(newProps, prevProps)) {
rerender()
}
也就是说,只要你传入的 mapStateToProps 结果没变,组件根本不会更新。
这就是 Redux 组件相比 MobX 更可控的地方:更新只发生在“你真的关心的 state 改了”的时候。
🔎 第六步:v7 / 未来版本支持 Concurrent 模式
React 新架构(如 Concurrent + Server Component)要求 state 更新是「延迟合并 + 不阻塞渲染」,这对 Redux 的订阅机制提出新挑战。
我们对 react-redux 做了:
- ✅ Context 分片更新支持
- ✅ useSyncExternalStore 支持(v8 完整兼容)
- ✅ 多组件共享 selector 缓存(useSelector with memo)
目标是:零额外更新、零冗余 re-render、天然类型推导。
📦 总结:connect 是结构性封装,而非逻辑注入
| 机制 | 目的 |
|---|---|
| Context + Subscription | 注入 store + 局部更新 |
| selectorFactory | 动态构建 props |
| useReducer 强制更新 | 避免无意义状态依赖 |
| shallowEqual | 精准对比,避免无效重渲染 |
| connectAdvanced | 统一封装所有生命周期与性能逻辑 |
Redux 是同步状态容器,React 是异步视图引擎,connect 是这两者的完美适配器。
⏭️ 下一篇预告
下一篇我们将进入Redux 架构最佳实践层面,站在真实项目的视角回答:
Reducer 怎么拆分才合理? 大型系统如何组织 action? Redux Toolkit 如何减少心智负担?
敬请期待: 第6篇:《Redux 架构最佳实践:如何构建可维护、可扩展的状态体系》