外观
React 组件设计与性能
- 状态:未准备
- 适用方向:前端 / Go 全栈
- 最近复习:待填写
- 下次复习:待安排
一句话回答
先按职责和状态归属设计组件,再用测量定位重复计算和过大更新范围;memo、useMemo、useCallback 是有成本的优化工具,不能代替正确的数据流。
原理解释
状态放在哪里?
只被单个组件使用的交互状态就近保存,多个同级组件协作时提升到最近公共祖先。跨页面共享的客户端状态可放 store;服务端数据还涉及缓存、去重、失效和重试,不应只当一个全局数组维护。
受控输入由 value 和 onChange 驱动,方便校验与联动;非受控输入通过 defaultValue 和 ref 读取,适合无需逐次驱动界面的表单场景。避免同一输入在生命周期中混用两套控制方式。
三种缓存工具
- memo:在 props 比较相等时通常可跳过父更新带来的重新渲染;自身状态和消费的 Context 仍可能触发更新。
- useMemo:缓存计算结果,用于昂贵计算或确有需要的引用稳定。
- useCallback:缓存函数引用,不是禁止函数表达式被求值,也不使函数内部计算自动更快。
jsx
const visibleItems = useMemo(
() => items.filter(item => item.name.includes(query)),
[items, query],
)
const onSelect = useCallback(id => setSelectedId(id), [])
// 只有消费方关心引用稳定时,缓存才可能带来实际收益。场景与边界
一个每次新建的对象 prop 就可能破坏 memo 的浅比较效果。自定义比较函数若忽略函数 prop,可能保留陈旧闭包。长列表虚拟化可减少 DOM,但要处理行高、滚动锚点、键盘交互;不能仅凭数据条数认定值得引入。
使用 React Profiler 比较相同交互的提交耗时与范围。React Compiler 是否启用要查构建配置,不因安装了 React 19 就假设已自动优化。
项目中的应用
参考 SimulSpeak 字幕展示 与 EinoTalk store 拆分,检查高频更新是否波及无关组件。虚拟列表和性能收益均需另行验证,不视为现有成果。
常见追问
- Context 为什么会引起更新? Provider 的 value 变化会使对应消费者更新;可按变化频率与职责拆分,或采用支持 selector 的外部 store。
- Zustand 解决什么? 提供组件外共享状态与订阅;仍需合理选择订阅切片,不能自动解决所有重渲染或服务端缓存问题。
- 什么时候不用缓存? 计算很便宜、依赖频繁变化、消费方不关心引用或测量无收益时。