React 项目越往后做,越容易发现真正难的不是单个组件,而是“逻辑怎样复用、状态怎样协作、边界怎样保持稳定”。Context、状态提升、组合模式、自定义 Hook 这些主题经常一起出现,不是巧合,而是因为它们都在回答同一个问题:当组件越来越多时,React 代码怎样继续保持可读和可组合。
为什么组件复用不是“抽个公共组件”这么简单?
因为复用真正复杂的地方,往往不是视觉,而是行为和状态。一个按钮、一个弹窗、一个表格壳层之所以能复用,不只是样子一样,而是:
- 输入边界稳定;
- 状态归属清楚;
- 交互意图明确;
- 不把特定页面的副作用偷偷带进去。
所以组件复用本质上不是 UI 重复利用,而是边界设计能力。
状态提升什么时候是好事?
状态提升的价值在于:当一份状态已经成为多个子组件的共同事实时,把它提升到共同父层能让协作更稳定。例如:
- 筛选栏和列表共享同一组查询条件;
- 多个字段共同决定某个表单状态;
- 弹窗和列表操作需要同步;
- 多个区域依赖同一份选中结果。
这时状态提升能帮助你守住单向数据流,让组件间关系更容易理解。
状态提升什么时候会开始变坏?
当状态被抬得过高,却没有真实共享收益时,常见后果包括:
- 父组件越来越重;
- 局部组件失去独立性;
- 无关区域也被一起带动更新;
- 页面和组件边界开始模糊。
所以状态提升不是默认更规范,而是“放到最低但又足够共享的那一层”才最稳。
Context 真正适合什么?
Context 最适合承接少量稳定共享的上下文信息,比如:
- 主题;
- 国际化信息;
- 当前认证上下文;
- 组件族内部上下文;
- 某些低频但需要跨层共享的能力。
它的价值在于避免层层透传,让树中较深位置也能拿到必要上下文。但它并不是“轻量全局 store”的万能替代。高频变化、复杂业务状态如果全压进 Context,后面通常会很难受。
组合模式为什么在 React 里很重要?
因为很多复用问题,并不适合靠继承或巨型通用组件解决。React 更自然的方式,是通过组合让:
- 父层组织结构;
- 子层承接局部内容;
- 组件间通过 props、children、render slots 一类模式协作。
组合模式真正带来的,是灵活而不失边界。它能让你构建出稳定骨架,同时把可变区域留给调用方决定。
自定义 Hook 的价值到底是什么?
自定义 Hook 的真正价值,不是“把代码挪个地方”,而是把一段围绕状态和副作用组织起来的能力,抽成可复用的逻辑单元。比如:
- 分页和查询逻辑;
- 表单提交流程;
- 权限判断;
- 某类请求与缓存行为;
- 弹窗开关与交互收口。
它的优势在于:逻辑能围绕能力聚合,而不是被拆散在不同组件里反复复制。
为什么很多自定义 Hook 抽出来以后反而更难懂?
最常见的问题是:
- 输入输出边界不清;
- 抽象过早;
- 逻辑仍然强绑定某个页面;
- 一个 Hook 里承担太多职责。
所以自定义 Hook 不是“看到重复就抽”,而是要看这段逻辑是否已经形成了稳定能力边界。
把这些能力放回项目里,最重要的判断是什么?
一个更稳的顺序通常是:
1. 先判断状态是否真的需要共享;2. 能靠状态提升解决的,先别急着上 Context;3. 少量稳定上下文再考虑 Context;4. 结构复用优先考虑组合模式;5. 逻辑复用再看是否值得抽自定义 Hook。
只要这个顺序不乱,复用和共享就不容易失控。
最常见的几个误区
1. 一有多层传值就直接上 Context
这通常会把局部问题过度全局化。
2. 看到重复逻辑就立刻抽 Hook
很多抽象会因为边界不稳定而失败。
3. 组件复用只看 UI,不看状态和副作用
后面很容易复用出一堆“看似通用,实则难用”的组件。
4. 状态提升没有上限
父组件很容易因此变成大容器。
总结
Context、状态提升、组合模式和自定义 Hook,本质上都在帮助 React 项目回答“逻辑怎样共享、边界怎样保持稳定”这个问题。状态提升适合共同事实,Context 适合少量稳定上下文,组合模式适合结构复用,自定义 Hook 则适合能力复用。只要始终先看边界再看 API,组件复用和状态协作就会顺很多。