一、React核心概念必考三连击
1. 说说React生命周期(必考知识点)
React 16.8版本后生命周期发生重大变化!!!类组件的生命周期分为三大阶段:
- 挂载阶段:
constructor()
→static getDerivedStateFromProps()
→render()
→componentDidMount()
- 更新阶段:
static getDerivedStateFromProps()
→shouldComponentUpdate()
→render()
→getSnapshotBeforeUpdate()
→componentDidUpdate()
- 卸载阶段:
componentWillUnmount()
(敲黑板)特别注意函数组件虽然没有生命周期方法,但可以通过useEffect
模拟。比如useEffect(() => {}, [])
就相当于componentDidMount
,这个对比面试官超爱问!
2. 虚拟DOM原理大揭秘
虚拟DOM的本质就是个JavaScript对象树,它的存在价值可不是为了快!!!(这点很多人搞错)主要解决两个问题:
- 平台抽象:让React可以跨平台渲染(比如React Native)
- 批量更新:通过Diff算法减少DOM操作次数
举个真实案例:当你在input
输入时,React会先更新虚拟DOM,然后通过diff算法发现只有输入框的value变化,最终只更新对应的真实DOM节点。这个机制在复杂表单场景下优势明显!
3. setState同步还是异步?
这道题能区分初级和中级开发!简单来说:
- 在React事件处理函数中:异步更新(多个setState会被合并)
- 在setTimeout/原生事件中:同步更新
实验代码演示:
handleClick = () => {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 输出旧值
setTimeout(() => {
this.setState({ count: this.state.count + 1 });
console.log(this.state.count); // 输出新值
}, 0);
}
二、Hooks面试连环问
1. useEffect的依赖数组怎么写?
这个陷阱题能刷掉50%的候选人!常见错误姿势:
useEffect(() => {
// 这里用了data.id
}, [data]); // 应该写成[data.id]
(血泪教训)曾经有个项目因为依赖数组写错导致内存泄漏,排查了整整两天!!!正确的做法是:把effect中用到的所有外部变量都放进依赖数组,实在不想更新就用useRef
。
2. useCallback和useMemo怎么选?
这两个Hook的区别就像咖啡和茶——看起来像但完全不一样:
useCallback | useMemo | |
---|---|---|
返回值 | 记忆化函数 | 记忆化值 |
适用场景 | 函数作为props传递时 | 复杂计算结果的缓存 |
典型用例 | 避免子组件不必要的重新渲染 | 过滤/排序大数据量列表 |
3. 自定义Hook开发实战
面试官可能会让你现场手写一个usePrevious
Hook:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
// 使用示例:const prevCount = usePrevious(count);
(加分项)可以说说项目中用过的自定义Hook,比如useFormValidation
表单校验Hook,或者useWindowSize
响应式布局Hook。
三、性能优化必杀技
1. React.memo的黄金法则
别滥用!!!只在以下情况使用:
- 组件props经常变化但渲染结果相同
- 组件渲染开销较大(比如复杂图表)
- 作为PureComponent的函数组件版
错误案例:
// 错误!内联函数会导致每次都是新props
const MemoComp = React.memo(({ onClick }) => { ... });
<MemoComp onClick={() => {}} />
2. 懒加载的正确姿势
结合Suspense和ErrorBoundary使用更安全:
const LazyComponent = React.lazy(() => import('./Component'));
function App() {
return (
<ErrorBoundary>
<Suspense fallback={<Spinner />}>
<LazyComponent />
</Suspense>
</ErrorBoundary>
);
}
3. 列表渲染优化秘籍
当处理1w+条数据时,别用Array.map
直接渲染!!!推荐方案:
- 虚拟滚动:react-window或react-virtualized
- 分页加载:滚动到底部加载下一页
- Web Worker:把复杂计算放到worker线程
曾经优化过一个商品列表页,用react-window把渲染时间从5秒降到200ms,用户留存率直接提升30%!(数据可视化场景特别明显)
四、项目经验灵魂拷问
1. 最复杂的组件怎么设计?
回答模板:
- 组件拆分成多个原子组件
- 状态管理方案选择(Redux/Context/Props)
- 性能优化措施
- 遇到的坑和解决方案
(真实案例)分享一个动态表单生成器的实现,如何通过JSON Schema渲染表单,处理嵌套字段校验,以及用Immer处理不可变数据。
2. 如何做技术选型?
展示你的决策框架:
- 团队熟悉程度(别用没人会的新轮子)
- 社区活跃度(GitHub stars/issues)
- 文档完整性
- 长期维护性
举个反例:曾经为了炫技用了某个新状态管理库,结果三个月后停止维护,被迫重构的血泪史...
3. 线上事故处理经验
考察点:debug能力 + 应急响应
经典回答结构:
- 监控告警(Sentry报警)
- 快速回滚(立即回退版本)
- 日志分析(定位到某个API请求失败)
- 修复验证(编写测试用例防止复发)
- 事后复盘(建立自动化测试流水线)
最后给面试者的建议:别死记硬背答案!!!现在的面试官更看重三点:
- 原理理解深度(能画Fiber树结构图加分)
- 工程实践能力(说清楚为什么选某个方案)
- 学习方法论(怎么快速上手新版本特性)
准备好你的"战争故事"——那些解决过的棘手问题,往往比标准答案更能打动面试官!祝大家面试顺利,斩获心仪offer~ 🚀
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。