React 性能优化

触发 React 组件的 Render 过程目前有三种方式,分别为 forceUpdate、State 更新、父组件 Render 触发子组件 Render 过程

优化技巧

  1. 跳过不必要的组件更新。这类优化是在组件状态发生变更后,通过减少不必要的组件更新来实现
  2. 提交阶段优化。这类优化的目的是减少提交阶段耗时
  3. 前端通用优化。这类优化在所有前端框架中都存在

跳过不必要的组件更新

PureComponent、React.memo

在 React 工作流中,如果只有父组件发生状态更新,即使父组件传给子组件的所有 Props 都没有修改,也会引起子组件的 Render 过程。从 React 的声明式设计理念来看,如果子组件的 Props 和 State 都没有改变,那么其生成的 DOM 结构和副作用也不应该发生改变。当子组件符合声明式设计理念时,就可以忽略子组件本次的 Render 过程。PureComponent 和 React.memo 就是应对这种场景的,PureComponent 是对类组件的 Props 和 State 进行浅比较,React.memo 是对函数组件的 Props 进行浅比较

shouldComponentUpdate

仅在「子组件使用的属性」发生改变时才返回 true,便能避免子组件重新 Render。

useMemo、useCallback 实现稳定的 Props 值

Hooks 按需更新

性能优化的话要知道一点

减少没必要的组件的渲染

把 React 比喻成一个大家族,假设妈妈在做饭,做好后,通知一声,大家来

如果做好一道,就喊一次:我做了 XX 菜,还有几道菜,其他人喊好的。其他人在这其中就是没必要说的,按照 React 的说法,就是没必要渲染

废话不多说,亮代码:

import React from 'react';

const Son = () => {
    console.log('son render');
    return <div>我是儿子,在玩电脑</div>;
};

const Daughter = () => {
    console.log('daughter render');
    return <div>我是女儿,在刷小红书</div>;
};

const Mother = () => {
    console.log('mother render');
    return <div>我是妈妈,在炒菜</div>;
};

const Father = () => {
    console.log('father render');
    return <div>我是爸爸,在看NBA</div>;
};

const Uncle = () => {
    console.log('uncle render');
    return <div>我是叔叔,在研究虚拟货币</div>;
};

const Aunt = () => {
    console.log('aunt render');
    return <div>我是婶婶,在带货直播</div>;
};

const Grandfather = () => {
    console.log('grandfather render');
    return <div>我是爷爷,在发呆</div>;
};

const GrandMother = () => {
    console.log('grandmother render');
    return <div>我是奶奶,在打电话</div>;
};

const Family = () => {
    return (
        <>
            <GrandMother />
        </>
    );
};

const App = () => {
    return <Family />;
};

memo 就是减少组件的没必要的渲染,做浅对比

函数式性能优化

主要是 hooks

useMemo、useCallback、memo

类组件性能优化

shouldComponentUpdate、pureComponent

shouldComponentUpdate 与 memo 的区别

案例分析

1000 条数据的解决方案——跳转

「性能优化」的核心应当是「不订阅视图无关的数据,以避免重复渲染」

而不是「订阅了视图无关的数据,用 useCallback/useMemo 来缓解性能问题」

React 渲染性能优化有三个方向:

  • 减少计算的量
    • 即减少渲染的节点或者降低组件渲染的复杂度
  • 利用缓存
    • 如何避免重新渲染,利用函数式编程的 memo 方式来避免组件重新渲染
  • 精确重新计算的范围
    • 绑定组件和状态关系,精确判断更新的”时机“和”范围“,只重新渲染”脏“的组件,或者说降低渲染范围

memo

与 shouldComponentUpdate 的效果一样

const areEqual = (prevProps, nextProps) => {
   // 返回结果和shouldComponentUpdate正好相反
   // 访问不了state
};
React.memo(Foo, areEqual);

参考资料

Last Updated:
Contributors: johan