主题
Hooks 的职责与使用边界
Hooks 让函数组件拥有状态和生命周期能力,但并不意味着所有逻辑都应该放进 useEffect。
先区分三类逻辑
- 渲染所需的原始状态使用
useState或useReducer。 - 可以从现有输入计算的值直接计算,必要时使用
useMemo。 - 需要与组件外部系统同步时才使用
useEffect。
tsx
function ProductList({ products, query }) {
const visibleProducts = products.filter((product) =>
product.name.includes(query)
)
return visibleProducts.map((product) => (
<ProductItem key={product.id} product={product} />
))
}这里的过滤结果是派生数据,不需要额外状态,也不需要 Effect。
自定义 Hook 的价值
自定义 Hook 用来复用有状态的逻辑,而不是复用渲染后的 UI。一个好的 Hook 会提供清晰的输入输出,并隐藏订阅、清理和异常处理等细节。
检查清单
- Effect 是否真的在同步外部系统?
- 依赖是否完整?
- 清理函数是否与建立订阅的过程对称?
- 这个状态能否由 props 或其他状态计算得到?

