你的 React App 可能做得太多了
Source: Dev.to
核心问题
大多数 React 应用执行的工作远超实际需求。这种隐藏的复杂性会逐渐演变为性能问题、技术债务以及开发者的挫败感。
当组件变得过大
一个看似简单的 UI 块——例如表单、按钮、模态框或列表——内部可能包含:
- 多个
useStateHook - API 调用
- 验证逻辑
- 条件渲染
- 错误处理
- 加载状态
- 副作用
- 动画
- 与全局状态的连接
看起来是小 UI 组件的东西,往往实际上是一个小型应用。
症状
- 开发时间更长: 本应几分钟即可阅读完的组件,现在需要花费更久的时间。
- 认知负担增加: 开发者必须跟踪状态更新、效果、副作用、条件渲染以及异步行为。
- 意外的副作用: 更改一个简单的 UI 元素可能会影响状态逻辑、API 调用、验证规则、全局状态以及其他组件。
- 团队警告: “除非绝对必要,否则不要触碰该组件。”
过度封装的后果
- 不必要的重新渲染
- 大量的状态更新
- 重复的 API 调用
- 低效的渲染循环
即使是现代的 React 优化也无法完全弥补结构不良的组件层次,导致 UI 变慢、交互卡顿以及调试困难。
常见的架构错误
在组件中直接添加功能
Need validation? Add a hook.
Need API data? Add another hook.
Need animation? Add a library.
Need caching? Add another layer.单独来看这些改动似乎无害,但随着时间推移,组件会累积职责,最终表现得像业务逻辑容器。
错误的做法
Component fetches data
Component validates input
Component manages state
Component renders UI更好的做法
- Services 负责 API 调用。
- Custom hooks 封装可复用的逻辑。
- Components 只专注于渲染数据。
明智地管理状态
并非所有事物都需要状态。自问:
- 这个值可以派生而不是存储吗?
- 可以从 props 计算得到吗?
- 可以在更高层处理吗?
减少不必要的状态可降低错误并简化调试。
有效使用自定义 Hook
自定义 Hook 功能强大,但过度使用可能会导致隐藏的复杂性:
- 数据流不清晰
- 逻辑间接
- 调试困难
Hook 应该简化逻辑,而不是使其模糊。应将其用于封装可重用行为,同时保持整体数据流的透明性。
结构化职责
| 责任 | 推荐位置 |
|---|---|
| UI 渲染 | 组件 |
| 验证逻辑 | 单独的自定义 Hook |
| API 调用 | 服务层 |
| 状态管理 | 中央存储(例如 Redux、Zustand) |
这种分离能够提供清晰、可扩展的结构。
AI 集成带来新复杂性
现代 React 应用越来越多地加入 AI 功能,例如:
- AI 生成的内容
- 预测性建议
- 智能 UI 决策
- 自动化工作流
这些会带来:
- 异步响应
- 动态 UI 行为
- 回退处理
- 输出的不确定性
如果现有架构已经超负荷,加入 AI 逻辑可能会加剧问题。保持核心结构的简洁变得更加关键。
有用的类比
- Dining area = UI 组件(专注于呈现)
- Kitchen = 业务逻辑、API、AI、数据处理
- Waiters = 通信层(状态管理、props)
当厨房放在餐厅内时,会导致混乱。相反,应将厨房独立出来,让服务员处理订单,让餐厅负责呈现餐点。
要点
- 避免在 UI 组件中塞入过多逻辑。
- 将关注点分离:渲染、数据获取、验证和状态管理应位于不同层级。
- 使用自定义 Hook 和服务,使组件保持简洁。
- 最小化不必要的状态。
- 从一开始就保持清晰的架构,为 AI 集成做好规划。
最好的 React 应用不是工作量最大的,而是把正确的事情放在正确的位置上。