一、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对象树,它的存在价值可不是为了快!!!(这点很多人搞错)主要解决两个问题:

  1. 平台抽象:让React可以跨平台渲染(比如React Native)
  2. 批量更新:通过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的区别就像咖啡和茶——看起来像但完全不一样:

useCallbackuseMemo
返回值记忆化函数记忆化值
适用场景函数作为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直接渲染!!!推荐方案:

  1. 虚拟滚动:react-window或react-virtualized
  2. 分页加载:滚动到底部加载下一页
  3. Web Worker:把复杂计算放到worker线程

曾经优化过一个商品列表页,用react-window把渲染时间从5秒降到200ms,用户留存率直接提升30%!(数据可视化场景特别明显)

四、项目经验灵魂拷问

1. 最复杂的组件怎么设计?

回答模板:

  1. 组件拆分成多个原子组件
  2. 状态管理方案选择(Redux/Context/Props)
  3. 性能优化措施
  4. 遇到的坑和解决方案

(真实案例)分享一个动态表单生成器的实现,如何通过JSON Schema渲染表单,处理嵌套字段校验,以及用Immer处理不可变数据。

2. 如何做技术选型?

展示你的决策框架:

  1. 团队熟悉程度(别用没人会的新轮子)
  2. 社区活跃度(GitHub stars/issues)
  3. 文档完整性
  4. 长期维护性

举个反例:曾经为了炫技用了某个新状态管理库,结果三个月后停止维护,被迫重构的血泪史...

3. 线上事故处理经验

考察点:debug能力 + 应急响应

经典回答结构:

  1. 监控告警(Sentry报警)
  2. 快速回滚(立即回退版本)
  3. 日志分析(定位到某个API请求失败)
  4. 修复验证(编写测试用例防止复发)
  5. 事后复盘(建立自动化测试流水线)

最后给面试者的建议:别死记硬背答案!!!现在的面试官更看重三点:

  1. 原理理解深度(能画Fiber树结构图加分)
  2. 工程实践能力(说清楚为什么选某个方案)
  3. 学习方法论(怎么快速上手新版本特性)

准备好你的"战争故事"——那些解决过的棘手问题,往往比标准答案更能打动面试官!祝大家面试顺利,斩获心仪offer~ 🚀


打酱油的仙人掌
1 声望0 粉丝