破、审题

答题思路:

  1. 优化时机
  2. 定位方式
  3. 常见坑
  4. 处理方案

    优化时机

    原理

    React 会构建、维护一套内部的 VDOM 树,因为大量 DOM 时,操作 DOM 树相对操作 JS 对象更慢,依据 VDOM 树生成的差异更新真实 DOM。当每一个组件的 props 或 state 变更时,React 会对比新旧元素,决定是否有必要更新真实 DOM。当它们不同时,React 会更新该 DOM,此过程被称为:协调。
    协调成本昂贵,若一次渲染的层级过深,就会阻塞 UI 主线程的执行,造成卡顿,引起页面帧率下降。

    时机

    业务在目标群体中的运行环境标准就是业务标准。

    定位方式

    还原场景、完整复现。
    工具:

  5. Chrome Performance 面板

  6. React Developer Tools 中的 Profiler 分析组件渲染次数、开始时间即耗时。
    React Profiler 官网文档介绍

    常见坑

  7. 单个组件的更新,却触发了大量无关组件更新,这就有问题了。

解决方案:React.memoPureComponent都是通过浅比较方式对比前后 props 和 state 的变化。

  1. 那在使用了如上两个方案后,是否会有失效的情况呢?

答:常见的坑就是使用 箭头函数。

  1. <ListItem
  2. key={id}
  3. onXXX={(id) => {...}}
  4. onXXXX={this.xxxx}
  5. />

以上代码,每次调用 render 函数时都会动态生成一个新的函数,函数的引用 变了,此时React.memo无效。
这种 JSX 问题好解决,将整个函数提取为一个 类属性的函数 即可。

  1. PureComponent中,每次调用 render 函数都会生成一个新的 data 对象,PureComponent破防了,若下层子组件没防护好,层层击穿,开始了昂贵的协调,如下代码:

    1. render() {
    2. const data = this.props.list.map(item => item)
    3. return (
    4. <子组件
    5. data={data}
    6. renderItem={this.renderItem}
    7. />
    8. )
    9. }

    处理方案

    React 在设计上是通过 数据变化引发视图层的更新。

    缓存

    reselect 工具;

    不可变数据

    ImmutableJS
    immerJS

    手动控制

    shouldComponentUpdate,render 阶段执行,此时形参(newProps, newState, newContext)

    答题

    如何避免重复渲染分为三个步骤:选择优化时机、定位重复渲染问题、引入解决方案。
    优化时机:需根据业务标准和页面性能数据分析,来决定是否有必要。若卡顿业务可接受,必做,下一步,定位。
    定位重复渲染问题:还原场景,复现问题,使用 Chrome Performance 面板、React Developer Tools 中的 Profiler 工具进行分析,对卡顿点、组件重复渲染次数及耗时排查性能问题。
    解决方案:PureComponentReact.memo等组件缓存 API,减少重新渲染。若错误使用,会使其无效,如 JSX 的属性是 箭头函数,或每次生成新的对象,那就破防了。
    针对这种破防,有三种解决方案:

  2. 缓存

  3. 不可变数据
  4. 手动控制

通过以上手段就可避免无效渲染带来的性能问题了。
面试 - 14- 如何避免重复渲染 - 图1