React 性能优化

Posted by Leonsux on May 31, 2022

避免不必要的组件更新。

将 props 设置为数组或对象

每次调用 React 组件都会创建新组件,就算传入的数组或对象的值没有改变,他们的引用地址也会发生改变,比如,如果按照如下的写法,那么每次渲染时 style 都是一个新对象

// 不推荐
<button style= />

// 推荐
const style = { color: 'red' }
<button style={style} />

// 不推荐
<button style={this.props.style || {} } />  

// 推荐
const defaultStyle = {}
<button style={this.props.style || defaultStyle } />

使用 PureComponent、React.memo、useCallback、useMemo、useContext 跳过不必要的组件更新。

通常当父组件更新时,子组件也会跟着更新,即使 props 没有变更。

使用 memo 包裹子组件,这样当父组件更新时,子组件的 props 没有更新,子组件便不会更新。当然只有当 props 为基础数据类型时才生效。如果传递参数为对象或者函数,依然有问题。

可以使用 useCallback 包裹函数,useMemo 包裹对象之后再传递给子组件。

import { useMemo, useState, useCallback } from "react";
import { Child } from "./child";

export const Parent = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('小明');
  // const [userInfo, setUserInfo] = useState({ name: "小明", age: 18 });
  const increment = () => setCount(count + 1);
  const userInfo = useMemo(() => ({ name, age: 18 }), [name]); // 当 name 变更时,重新执行useMemo第一个参数(函数),得到新的 userInfo

  const onClick = useCallback((name: string) => {
    setName(name);
  }, []);

  return (
    <div>
      <button onClick={increment}>点击次数{count}</button>
      <Child
        onClick={onClick}
        userInfo={userInfo}
      />
    </div>
  );
};
import { memo } from "react";

export const Child = memo(
  (props: { userInfo: { name: string; age: number; onClick: (value: any) => void; } }) => {
    const { userInfo, onClick } = props;
    console.log("渲染了", userInfo);
    return (
      <>
        <div>名字 {userInfo.name}</div>
        <div>年龄{userInfo.age}</div>
        <button onClick={onClick}>按钮</button>
      </>
    );
  }
);


列表渲染使用 key 属性

给列表项设置唯一 key,在 diff 算法中,会用 key 作为唯一标识优化渲染。

参考

https://juejin.cn/post/7039256825656524807

https://juejin.cn/post/6935584878071119885