React 组件设计原则
React 组件设计的稳定原则:职责边界、状态 ownership、最小 props contract、组合、受控/非受控边界、副作用隔离与可验证性。
#frame
#react
#synthesis
#growing
[!info] related notes
- 所属 MOC: React MOC
- 状态模型: React props、state 与 ref
- 状态位置: 状态上提 vs Colocation
- 渲染: 组件渲染与重渲染
- 表单边界: 受控与非受控组件
React 组件设计原则
核心目标
好组件不是“代码少”,而是:
- ownership 清楚;
- public contract 稳定;
- 内部细节不外泄;
- 可组合;
- 可测试;
- 改一个 feature 时影响范围可预测。
1. 先定义职责边界
一个组件应该围绕一个稳定 UI / interaction responsibility。
警报信号:
- 同时请求数据、做复杂转换、管理多个表单、控制路由和布局;
- props 数量不断增加只是为了控制内部特例;
- 修改一个小行为需要碰很多不相关分支。
这通常说明 boundary 太宽。
2. State 放在真正拥有它的地方
原则不是“尽量上提”,而是:
state 尽量靠近真正需要读写它的最小共同 owner。
只有多个兄弟确实需要共享时才上提。
如果 state 被放得太高:
- rerender 范围变大;
- ownership 模糊;
- cleanup/lifecycle 变复杂。
3. Derived Data 不要重复存
如果一个值能从 props/state 直接计算出来,通常不应该再维护第二份 state。
否则容易形成:
source A ↔ duplicated state B
两份 truth 需要人为同步。
4. Props 是 Public API
props 应表达组件真正需要的输入,而不是暴露内部实现按钮。
坏信号:
- 十几个 boolean 相互组合;
- 父组件需要知道子组件内部状态机;
- prop 名称与内部 DOM/CSS 实现绑定。
更稳的方向:
- semantic props;
- event callback;
- slot/children/composition;
- 明确 controlled contract。
5. Composition 优于巨型万能组件
React 更自然的复用方式是组合:
small primitives → domain components → page composition。
不要用一个万能组件承载所有业务变体。
6. Controlled / Uncontrolled 边界
组件需要明确:
- value authority 在父级;
- 还是组件自己持有内部 state。
最危险的是父子双方长期维护两份同名值,却没有清楚同步 contract。
7. Side Effect 与 Render 分开
render 应尽量保持纯。
真正外部系统同步才进入 Effect:
- network subscription;
- DOM imperative integration;
- timer;
- browser API。
不要把普通 derived value 和 event action 习惯性塞进 useEffect。
8. 数据获取与展示不要机械绑定
“容器/展示组件”不是必须固定二分,但要保持:
- server state ownership 清楚;
- UI component 不强依赖某个特定 endpoint;
- domain transform 可以独立测试。
9. 可验证性是设计反馈
如果一个组件很难测试,常见原因是:
- 依赖太多全局状态;
- side effect 与 render 混在一起;
- contract 太隐式;
- 一个组件承担过多职责。
测试困难本身可以作为边界设计信号。
学习检查
- 为什么“状态尽量上提”不是完整设计原则?
- derived data 为什么通常不应该重复存 state?
- props 为什么可以看作组件 public API?
- 大量 boolean props 暗示什么设计问题?
- controlled/uncontrolled 最危险的混合状态是什么?
- 为什么普通计算不应该默认放进 useEffect?
- 给一个同时请求数据、编辑表单、控制 Dialog 和渲染表格的组件,设计一个更清晰的拆分方案。