React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > React渲染优化

React渲染的优化方案

作者:brandonxiang

react的渲染机制是非常独特的,有别于 Vue 框架的渲染次数的优化计算,React 很久以来就有PureComponent、shouldUpdate,本文小编给大家介绍了React渲染的优化方案,需要的朋友可以参考下

一、引子

react的渲染机制是非常独特的,有别于 Vue 框架的渲染次数的优化计算。React 很久以来就有PureComponent、shouldUpdate。Function component 又有了memo、useMemo、useCallback 这样的函数工具,让它成为有一定深度的前端框架。

怎么使用 useMemo 和 useCallback 是我们值得思考的点。

二、代码范式

首先,假设大家对 React 都有一个基础的入门水平,所以本文不再赘述“useMemo 和 useCallback ”基本用法。

2.1 Memo 缓存组件

引起重渲染的最常见的情况是,组件的 props。memo包裹着函数组件,针对props 参数的浅对比。

子组件的渲染有些情况,子组件控制不住,它受到父组件的参数影响。

function _Boxes({ boxes }: {
  boxes: {
    flex: number;
    background: string;
  }[]
}) {
  return (
    <div className="boxes-wrapper">
      {boxes.map((boxStyles, index) => (
        <div className="box" style={boxStyles} key={index} />
      ))}
    </div>
  );
}

const Boxes = memo(_Boxes);

2.2 父组件层面,对象使用 useMemo

作为 Box 的父组件,boxes 的传参是一个对象,每次改变,它会生成一个全新的对象。这里要对 boxes 对象使用缓存(useMemo)。这样,age 的改动将不会影响到 Box 的重渲染。

function App() {
  const [age, setAge] = React.useState(0);
  const [boxWidth, setBoxWidth] = React.useState(1);

  const id = React.useId();

  // Age 属性的变更不会影响 boxes 属性变化
  const boxes = useMemo(() => {
    return [
      { flex: boxWidth, background: 'hsl(345deg 100% 50%)' },
      { flex: 3, background: 'hsl(260deg 100% 40%)' },
      { flex: 1, background: 'hsl(50deg 100% 60%)' },
    ];
  }, [boxWidth]);

  return (
    <>
      <Boxes boxes={boxes} />

      <section>
        <button onClick={() => {
          setAge(age + 1)
        }}>
          Increment age
        </button>
        <p>Hello! You are {age}.</p>
      </section>

      <section>
        <label htmlFor={`${id}-box-width`}>
          First box width:
        </label>
        <input
          id={`${id}-box-width`}
          type="range"
          min={1}
          max={5}
          step={0.01}
          value={boxWidth}
          onChange={(event) => {
            setBoxWidth(Number(event.target.value));
          }}
        />
      </section>
    </>
  );
}

2.3 context provider 最好用 useMemo

同理,参考《How To useContext With useReducer》,context provider 的 value 参数是一个很容易被遗忘的点,provider 可能会传入一个对象,利用useMemo 或者 useCallback 来保护 App 组件不会做出过多重渲染。

const Main = () => {
  const [state, dispatch] = useReducer(reducer, { age: 42 });
  
  // 利用useMemo 或者 useCallback 来保护 Context 不会做出过多重渲染
  const contextValue = useMemo(() => {
    return { state, dispatch };
  }, [state, dispatch]);
  
  return (
    <MyContext.Provider value={contextValue}>
      <App />
    </MyContext.Provider>
  )
}

2.4 其他

还有一种特殊情况是:不规范、分批的 Context 调用导致了页面的重新渲染。针对一些老旧项目,以前的业务逻辑导致 Context 的调用混乱,已经不是前面几种方法能够解决的。

解决方法:改动代码,把多次 Context 调用整合为一次。

三、补救防范

3.1 断点查看调用堆栈

利用 Chrome 原生调试工具打断点,看每一行代码的堆栈信息。这种方式最为原始但是它往往“行之有效”。

3.2 devtool 查看渲染次数和渲染堆栈

React Devtool 的 Profiler 能协助我们排查 React 渲染次数和渲染堆栈。

同时,我们还能够通过“highlight updates when components render”来可视化整个渲染过程。

3.3 渲染打印工具

ahooks的useWhyDidYouUpdate

该函数能够帮助开发者排查是哪个属性改变导致了组件的 rerender,但是更多集中在 props、state,开发者需要主动去缩小范围,它起到辅助打印的工作,如果是 Context 或者更外侧的数据变动,效果不见得达到效果。

Welldone Software 的 why-did-you-render

该工具能全局打印 rerender 日志,但是在复杂项目当中,它的打印较为混乱,不一定能够很好的发现问题。

四、总结

React 的渲染优化有非常多篇博客已经聊过,但是还是“No Silver Bullet”,没有最佳方案。特别在一些数据流非常复杂的前端工程项目当中。

React 的前端项目能够划分为:聪明组件和懒惰组件。聪明组件负责的内容是页面逻辑的数据流向,懒惰组件负责的是样式的渲染,数据流越是清晰,代码可维护性越强。

以下是我个人的代码编写建议:

虽然有很多分析工具,但是它们更多是辅助,最重要还是要通过人工分析。重点要分析出渲染次数过多的代码,做出针对性地处理。

以上就是React渲染的优化方案的详细内容,更多关于React渲染优化的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文