深色模式
渲染、性能与并发
21. React 如何判断状态是保留还是重置?
展开答案与追问
参考答案: 状态与渲染树中的组件身份关联,主要考虑位置、类型和 key。相同位置与类型通常保留状态;改变类型或 key 会重建。不要在父组件函数体内定义组件类型,否则每次可能产生新类型并重置后代状态。
追问与易错点: 案例:聊天对象变更时用稳定的联系人 key 重置输入草稿。状态保留与重置
22. 父组件更新是否意味着所有子组件 DOM 都变化?
展开答案与追问
参考答案: 父组件更新通常会让 React 继续计算其后代,但可能通过复用元素、memo 或其他优化跳过部分工作。即使子组件函数执行了,只要协调结果没有宿主变化,也不需要改 DOM。函数调用次数、协调成本与 DOM 修改是三种不同观察。
追问与易错点: 排障先用 Profiler 找出昂贵提交与组件,不要仅凭 console.log 次数判断性能。
23. useTransition 与 useDeferredValue 有什么区别?
展开答案与追问
参考答案: useTransition 用 startTransition 标记非紧急状态更新并提供 pending 状态;useDeferredValue 让某个值的非紧急消费可以滞后。两者用于保持关键交互响应,不是定时防抖,也不会自动减少请求次数。
追问与易错点: 输入框自身受控值要及时更新,昂贵结果可延迟。Transition 的异步 Action、await 后更新及请求顺序应按版本规则处理。useTransition
24. 并发渲染等于多线程渲染吗?
展开答案与追问
参考答案: 不等于。客户端主要是可中断、可恢复或可放弃的渲染工作,允许更紧急的更新先完成。常规 JS 仍受主线程执行模型约束,长时间同步计算不会因套了 startTransition 就自动搬到 Worker。
追问与易错点: 追问:如果昂贵计算发生在 startTransition 回调内,它仍会同步执行;优先级主要作用于 React 安排的更新。
25. Strict Mode 为什么会出现重复日志或请求?
展开答案与追问
参考答案: 开发检查会额外执行部分纯计算和 Effect 的设置/清理,以发现不纯渲染和清理缺失。应保证订阅可撤销、请求结果不会过期写入,而不是用全局标记跳过检查。具体额外检查还受 Strict Mode 放置位置影响。
追问与易错点: 它不是生产环境“永远渲染两次”的承诺;不要依赖固定调用次数写业务。
26. 如何避免 Effect 请求竞态与旧闭包?
展开答案与追问
参考答案: 将请求身份与依赖绑定,清理时取消旧请求或使旧结果失效,写入前确认仍属于当前请求。订阅回调如果只需更新旧状态,使用函数式更新;其他场景明确依赖关系或最新值读取策略。
追问与易错点: 不要把所有变量放 ref 来绕过响应式依赖;那可能隐藏真正需要重新同步的变化。
27. useSyncExternalStore 为什么存在?
展开答案与追问
参考答案: 外部可变 store 不由 React state 完全控制,需要一致的订阅与快照协议。该 Hook 接收 subscribe、getSnapshot,以及服务端场景的 getServerSnapshot,让 React 在渲染过程中检查快照一致性。
追问与易错点: getSnapshot 在数据未变时要返回稳定快照,不能每次都无条件创建新对象。API
28. SSR、hydration 与 Server Components 有什么区别?
展开答案与追问
参考答案: SSR 把 UI 渲染成 HTML,hydration 在客户端关联行为;Server Components 在服务端执行组件并产出框架可消费的组件结果,减少部分客户端代码需求。两者可以配合,但不是同一个机制。客户端组件也可能参与初始服务端 HTML 输出。
追问与易错点: 服务端组件不能直接使用客户端状态和 DOM;服务端数据访问仍需鉴权。采用方式依赖框架。官方介绍