React15 - React Redux组件模式性能对比
模式一:单容器 + 多展示组件(Props Drilling 模式)
这是比较传统的 React 组件通信方式。只有一个顶层容器负责与 Redux Store 连接,获取所有数据,然后通过 props 一层层传递给内部的展示组件。
graph TD
subgraph Redux Store
A[全局State]
end
subgraph React组件树
direction TB
B[顶层容器组件<br>connect到Redux<br>负责获取所有数据] -- 通过props传递所有数据 --> C[中间组件<br>只做传递]
C -- 通过props传递数据 --> D[展示组件A]
C -- 通过props传递数据 --> E[展示组件B]
end
B -.->|订阅整个数据切片| A
这种方式存在几个潜在的性能问题:
- 连坐效应:只要
mapStateToProps返回的任何一个数据发生变化,整个顶层容器及其下所有子组件都会触发重新渲染。 - 不必要的渲染:如果只有组件B的数据变了,但组件A和中间组件也会跟着重新渲染,造成了性能浪费。
- 耦合度高:中间组件承担了转发props的任务,使得组件复用和重构变得困难。
模式二:多容器 + 多展示组件(嵌套容器模式)
这种模式下,不仅顶层是容器,内部的组件如果自身需要数据,也会通过 connect 直接连接到 Redux Store,直接从 Store 获取自己的数据。
graph TD
subgraph Redux Store
A[全局State]
end
subgraph React组件树
direction TB
B[顶层容器组件<br>connect到Redux<br>获取部分数据] --> C[子容器组件A<br>connect到Redux<br>获取自己的数据]
B --> D[子容器组件B<br>connect到Redux<br>获取自己的数据]
C --> E[展示组件A1]
D --> F[展示组件B1]
end
B -.->|订阅数据切片1| A
C -.->|订阅数据切片2| A
D -.->|订阅数据切片3| A
这种方式对性能更友好的原因在于:
- 精确渲染:每个容器组件只订阅自己关心的那部分状态。当 Redux Store 中的某个数据变化时,只有订阅了该数据的特定容器组件会重新渲染,其他组件不受影响。
- 避免 Props Drilling:数据不再需要经过中间层组件传递,减少了中间层的渲染压力和代码耦合度。
- 性能优化:
connect函数内部已经做了高度优化(如默认的pure: true),它会通过浅比较来决定是否需要重新渲染,进一步避免了不必要的渲染。
深度分析:为什么“多连接”反而性能更好?
你可能会想,connect 本身是一个高阶组件,多几个 connect 不是会增加组件嵌套和复杂度吗?
关键在于 connect 的实现机制。react-redux 的 connect 函数不仅仅是将 Redux 的 state 映射到 props,它还做了两件非常重要的事情:
- 细粒度的订阅:每个
connect的组件都会在 Redux Store 上建立一个独立的订阅。当dispatch一个 action 后,Redux 会通知所有订阅者,但connect组件会先检查自己关联的 state 切片是否真的变了。只有真正变化了,才会触发该组件的重新渲染。 - 内置的
shouldComponentUpdate:connect生成的组件内部实现了shouldComponentUpdate逻辑,对新旧 props 和 state 进行浅比较。如果从 Redux 获取的数据没有变化,这个组件就不会重新渲染,从而阻断了它下面整个组件树不必要的更新。
因此,粒度更细的连接(模式二)实际上是把“是否需要更新”的判断逻辑,从顶层的一个大组件,下放到了每个需要数据的子组件自己身上。这就像把一支大军队化整为零,各自为战,反应更灵活,避免了“牵一发而动全身”的低效局面。
结论与建议
对于你的问题,结论非常明确:
- 性能上:第二种模式(一个container导入2个container)通常优于第一种。它能有效减少因props drilling和不必要的顶层重渲染带来的性能损耗。
- 官方推荐:Redux 官方早期曾强调“顶层有一个容器组件”的模式,但后来已将其视为一种误解,并更正为鼓励开发者在需要的地方使用
connect创建多个容器组件。 - 最佳实践:在实际开发中,建议采用混合模式。一个常见的策略是“每个页面或独立功能模块使用一个顶层容器,页面内多个相互独立的数据区块,则各自使用自己的子容器”。这样既能保证数据流向清晰,又能最大化应用性能。

浙公网安备 33010602011771号