React中使用useState透传props做全局状态管理是否存在非最优问题?
基于useState+props透传实现全局状态的问题分析
这种方案在小型项目、组件层级浅的场景下完全可用,但确实存在多个非最优的问题,在中大型项目里缺陷会被明显放大:
- Props 透穿(Props Drilling)负担重
如果要使用全局状态的组件和App组件之间隔了多层中间组件,所有中间层就算不需要用到这些状态,也必须额外接收并逐层传递masterStates、masterFunctions两个props。后续新增全局状态、修改状态字段名时,所有涉及到的中间层组件都要同步修改,维护成本会随组件层级和状态数量指数级上升。 - 容易触发不必要的组件重渲染
你示例中的masterStates、masterFunctions都是在App每次渲染时重新生成的对象,引用地址每次都会变化:- 如果App本身有其他状态更新触发重渲染,所有接收这两个props的子组件不管有没有用到变更的状态,都会被迫重渲染
- 就算你用
React.memo对子组件做渲染优化,也会因为props引用每次变化而失效,项目体积变大后性能损耗会非常明显
- 顶层组件耦合度过高,可维护性差
所有全局状态、状态修改逻辑都堆在App组件里,状态量一多App组件会变得极其臃肿,后续状态拆分、逻辑迭代都会受顶层组件的限制,代码耦合度很高。 - 调试、类型定义成本高
用TypeScript开发时,每一层中间组件都要重复写这两个props的类型定义,冗余代码极多;排查状态变更问题时,只能顺着props传递链路逐层向上溯源,没有配套的调试工具可以直接定位状态修改的触发点。
如果你的项目规模极小,组件层级不超过3层,全局状态数量在5个以内,这种方案反而比引入Context、状态管理库的方案更轻量,没有额外的依赖和学习成本,完全可以正常使用。
如果要继续用这个方案,可以做两个小优化:
- 用
useMemo包裹masterStates,只有依赖的counterA、counterB变化时才更新对象引用 - 不要把setter包在
masterFunctions对象里,直接单独传递setCounterA、setCounterB,因为useState返回的setter本身引用是稳定的,不会导致不必要的重渲染
内容的提问来源于stack exchange,提问作者Jellohouse
相关产品推荐
相关产品推荐

