返回专题首页

React 专题

Context 与组件复用:状态提升、组合模式、自定义 Hook

React 项目越往后做,越容易发现真正难的不是单个组件,而是“逻辑怎样复用、状态怎样协作、边界怎样保持稳定”。Context、状态提升、组合模式、自定义 Hook 这些主题经常一起出现,不是巧合,而是因为它们都在回答同一个问题:当组件越来越多时,React 代码怎样继续保持可读

React 专题第 08 篇 / 26 篇5 分钟

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,组件复用和状态协作就会顺很多。