深浅色
React(背诵版)
1. 一次渲染的完整流程
- 触发:setState / 父组件重渲染 / forceUpdate -> 交给 Scheduler 调度。
- render 阶段:构建 Fiber 树、diff,可中断,必须纯计算不能有副作用。
- commit 阶段:操作 DOM、执行 layout effect 和 passive effect,不可中断。
- 追问:render 阶段为什么要可中断?-> 让输入等高优先级更新插队,避免掉帧。
2. Diff 与 key
- 只做同层比较,不跨层级移动;类型不同直接销毁重建子树。
- key 标识元素身份。用 index 当 key,列表增删时会错位,导致 state 复用错对象、输入框内容错乱。
- 追问:key 相同但类型变了?-> 销毁旧的、创建新的。
3. Hooks 的实现原理
- 每个函数组件对应一个 Fiber,Fiber 上挂 hooks 链表,useState 按调用顺序取节点。
- 所以不能在条件或循环里调用 Hooks,顺序错乱会让 state 串位。
- 追问:为什么 setState 后立刻读 state 还是旧值?-> 闭包捕获的是本次渲染的快照。
4. useEffect
- 执行时机:commit 之后、浏览器绘制之后(异步);useLayoutEffect 在 DOM 变更后、绘制前同步执行。
- 依赖数组:不传 -> 每次都跑;空数组 -> 只跑一次;有依赖 -> 变化才跑。
- 清理函数在下次 effect 执行前或卸载时调用。
- 追问:什么时候必须用 useLayoutEffect?-> 要读布局(offsetWidth)并同步改 DOM,避免闪烁。
5. 闭包陷阱
- 定时器 / 事件监听里拿到的是创建时的 state 快照。
- 解决:依赖数组补全、用 useRef 保存最新值、用函数式更新
setX(v => v + 1)。 - 追问:setInterval 里 state 永远是 0 怎么办?-> 用 ref 或函数式更新,或每次依赖变化重建 interval。
6. memo / useMemo / useCallback
- memo 对 props 做浅比较;useMemo 缓存计算结果;useCallback 缓存函数引用。
- 负优化场景:依赖频繁变化、计算本身很便宜、子组件本来就会重渲染。
- 判断标准:先用 Profiler 测,再优化,别凭感觉加。
- 追问:useCallback 依赖写错为什么更糟?-> 依赖变就重建函数,子组件的 memo 全部失效。
7. 受控 vs 非受控
- 受控:value 由 state 驱动、onChange 更新,单向数据流、方便校验;缺点是每次输入都重渲染。
- 非受控:defaultValue + ref 读取,性能好但难做联动校验。
- 追问:受控输入卡顿怎么优化?-> 局部 state、useDeferredValue,或改成受控 + 非受控混合。
8. 状态管理选型
- Context:适合低频变更的全局数据(主题、用户),高频变更会让所有消费者重渲染。
- Zustand / Jotai:轻量、按需订阅、无 Provider 嵌套,适合中小项目。
- Redux Toolkit:强约束、可调试、中间件生态,适合大团队复杂状态。
- 追问:服务端状态为什么不用 Redux?-> 用 TanStack Query / SWR,缓存、重试、失效交给专门库。
9. React 18 并发特性
- 自动批处理:setTimeout / Promise 里的多次 setState 也合并。
- startTransition / useTransition:把更新标记为低优先级,可被打断。
- Suspense:loading 状态交给框架管理。
- 追问:并发渲染会改变结果吗?-> 不会,只是调度优先级;副作用仍在 commit 阶段。
10. SSR 与水合
- 流程:服务端 renderToString 出 HTML -> 浏览器先展示 -> 加载 JS 后 hydrate 绑定事件。
- 水合不匹配的常见原因:Date.now / 随机数 / localStorage 在服务端没有、HTML 嵌套非法。
- 解决:客户端专属内容放到 useEffect 里渲染,或加 suppressHydrationWarning。
- 追问:为什么不直接重建 DOM?-> 重建会丢失已加载的 DOM 和用户输入,hydrate 是复用。
11. 虚拟滚动
- 原理:只渲染可视区 + 缓冲区的元素,用占位撑起总高度,滚动时按 scrollTop 算起始 index。
- 难点:不定高要维护位置缓存或实测;快速滚动要节流;key 用数据 id。
- 追问:能用 content-visibility: auto 代替吗?-> 简单场景可以,复杂列表和精确定位还是虚拟滚动可控。