一、React 基础(详细版)
1. React 是什么?核心特点
React 是声明式 UI 库特点:
- 声明式:描述想要什么,不用操作 DOM
- 组件化:可复用、独立维护
- 单向数据流:父 → 子,可预测
- 虚拟 DOM + Fiber:高效更新、可中断渲染
- JSX:HTML 写在 JS 里,编译成 createElement
2. 为什么 key 不能用 index?
diff 靠 key 判断节点复用
- 数组增删前置 → index 错乱
- 导致:组件状态错位、DOM 复用错误、渲染 bug正确:唯一稳定业务 id
3. 受控 vs 非受控组件
- 受控:value 绑定 state,onChange 更新 → 完全可控、推荐
- 非受控:用 useRef 取值,state 不绑定 → 简单场景、快
4. 合成事件和原生事件区别
- 合成事件:React 自己实现、事件委托、性能高、冒泡
- 原生事件:绑定真实 DOM
- 执行顺序:原生先执行 → 合成后执行
- 阻止冒泡互不生效
二、Hooks 全家桶(面试核心・详细)
1. useState
- 产生局部状态
- 更新异步批量,不立即改变
- 状态不可变,必须新引用
- 函数式更新:setCount (pre => pre + 1) 解决闭包
2. useEffect
副作用:请求、订阅、DOM 操作执行时机:
- 空依赖:挂载 + 卸载
- 有依赖:依赖变化执行
- 返回函数:清理副作用(防内存泄漏)坑:漏依赖 → 闭包拿到旧值
3. useLayoutEffect
- 同步执行、DOM 绘制前
- 适合改 DOM、防止闪烁
- 比 useEffect 慢,优先用 useEffect
4. useRef
- 存值:跨渲染不变、不触发更新
- 拿 DOM 元素
- 穿透闭包
5. useMemo / useCallback
- useMemo:缓存计算结果,减少重算
- useCallback:缓存函数引用 ,防止子组件重复渲染注意:有成本,不要滥用
6. Hooks 使用规则
- 只在顶层调用
- 不在条件、循环、嵌套里用原因:依赖链表顺序不能乱,乱了状态错位
7. 闭包陷阱怎么解决?
- 加全依赖
- useRef 存最新值
- useReducer 摆脱闭包
三、React 底层原理(二面必考・详细)
1. 虚拟 DOM
用 JS 对象描述 DOM好处:
- 减少频繁真实 DOM
- 跨平台
- 便于 diff 计算
2. Diff 算法原理
同层比较 + 不跨层级流程:
- 类型不同 → 直接销毁重建
- 类型相同 → 对比属性
- 列表靠 key 找复用节点复杂度优化到 O(n)
3. Fiber 架构(重点背)
解决旧 React 一次性渲染卡死主线程两个阶段:
- Render 阶段(可中断、分片、优先级)
- 遍历、diff、构建 Fiber 树
- Commit 阶段(不可中断)
- 一次性更新 DOM、布局、绘制
4. React 更新流程
触发 setState→ 生成更新任务→ Fiber 调和(可中断)→ 收集 DOM 变更→ Commit 一次性渲染→ 浏览器绘制
四、性能优化(面试官最爱追问)
完整优化套路(背这一段)
- 拆分组件、状态下放:减少父渲染牵连子
- React.memo + useCallback + useMemo:阻断无效渲染
- 合理拆分 Context:避免全局一起刷新
- 懒加载:React.lazy + Suspense
- 长列表优化:虚拟滚动,只渲染可视区
- 减少重排重绘:批量 DOM、脱离文档流
- 图片 / 资源优化:懒加载、预加载
五、React 18 必问(2026 大厂高频)
1. 并发渲染 Concurrent Mode
渲染可中断、可优先级插队保证输入响应不卡顿
2. 自动批处理
Promise /setTimeout 里的 setState 也合并减少渲染次数
3. useTransition
区分紧急更新 / 非紧急更新例子:搜索输入高优、列表渲染低优
4. useDeferredValue
延迟一个值的更新,不阻塞 UI
5. Suspense
等待异步资源(接口 / 懒组件)显示 fallback
6. createRoot
替代旧 render,开启 18 所有新特性
六、状态管理(对比详细)
- 局部:useState /useReducer
- 简单全局:Zustand(轻、快、无 Context 嵌套)
- 大型项目:Redux Toolkit(规范、调试、中间件)
- 跨组件:拆分 Context,避免整体重渲染
七、高频问答题(详细标准答案)
1. setState 同步还是异步?
- 合成事件、hooks、18 内部:异步批量
- 原生事件、定时器、请求回调:同步目的:合并更新、提升性能
2. useEffect 依赖不写会怎样?
闭包陷阱,永远拿到旧变量,逻辑错乱
3. useMemo 什么时候不用?
简单计算、渲染成本低------ 缓存成本 > 收益,反而变慢
4. Context 为什么一改全渲染?
Context value 引用变 → 所有消费子树重新渲染解决:拆分多个 Context、原子化状态
八、必手写 6 个(附思路)
- useDebounce(防抖)
- useThrottle(节流)
- useFetch(loading / error / abort)
- useLocalStorage(持久化)
- 简易 useMemo /useCallback
- 虚拟列表核心:可视高度 + 滚动偏移 + 切片渲染