react 性能优化 shouldComponentUpdate ,PureComponent.memo,callback,callmemo

132 阅读3分钟

本文章参考 大神juejin.cn/post/684490… ,以及react官网

shouldComponentUpdate

shouldComponentUpdate 是函数式组件生命周期的方法之一,通过该方法可以控制组件是否应该更新来优化组件的渲染

image.png

该函数接收 nextProps,nextState . 可以通过比较 当前的state 和nextState,当前的props 和nextProps 是否相等,返回true/false 控制是否render

    class MyComponent extends React.Component {
      shouldComponentUpdate(nextProps, nextState) {
        // 执行自定义逻辑来判断组件是否应该更新
        // 返回true允许组件更新,返回false阻止组件更新

        // 例如:只有特定属性的值发生变化时才更新组件
        if (this.props.myProp !== nextProps.myProp) {
          return true;
        }

        // 例如:只有状态发生变化时才更新组件
        if (this.state.myState !== nextState.myState) {
          return true;
        }

        // 默认情况下,对于任何其他改变都更新组件
        return true;
      }

      render() {
        // 正常渲染组件
        return <div>My Component</div>;
      }
    }

注意shouldComponentUpdate 虽然可以提高性能,但代码复杂度会很高,例如我有多个props 或者多个state 需要控制渲染,则需在shouldComponentUpdate 定义多个,那我们就想这有没有能自动帮我们判断的方法呢?PureComponent 可以解决当前问题

PureComponent

在类式组件中,当 props 和 state 与之前保持一致时会跳过重新渲染。

import { PureComponent, useState } from 'react';

class Greeting extends PureComponent {
  render() {
    console.log("Greeting was rendered at", new Date().toLocaleTimeString());
    return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
  }
}

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

以上例子中:我们定义了MyApp(父组件) 以及Greeting 子组件(继承PureComponent). 当父组件更改状态name,address时父组件会重新渲染,子组件只在name 改变时(即传入的props 改变了)才会渲染

memo

以上讨论的都是类式组件优化问题,如果在函数式组件中应该怎么做呢,就是使用memo

memo 是一个高阶组件(Higher-Order Component,HOC)或称为函数, ,用于优化函数式组件的性能。memo 函数可以使函数式组件只在其属性发生更改时进行重新渲染,类似于类组件中的 PureComponent。 将对比 PureComponent

import { useState,memo } from 'react';
const Greeting = memo(function Greeting({name}){
  console.log("Greeting was rendered at", new Date().toLocaleTimeString());
  return <h3>Hello{name && ', '}{name}!</h3>;
})

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

useMemo

useMemo 是一个 React Hook,它在每次重新渲染的时候能够缓存计算的结果。 useMemo(calculateValue, dependencies) useMemo 接受两个参数:计算函数和依赖项数组。

使用注意:

  • 传入 useMemo 的函数会在渲染期间执行,不要在这个函数内部执行与渲染无关的操作
  • 如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值
const [count, setCount] = useState(0); 
const userInfo = { age: count, name: 'Jace' } 
return <UserCard userInfo={userInfo}>
const [count, setCount] = useState(0); 
const userInfo = useMemo(()=>{
return { age: count, name: 'Jace' } 
},[count])
return <UserCard userInfo={userInfo}>

上面的代码状态改变每次都会产生一个新的userInfo 而下面的代码count 改变才会产生新的userInfo

我们可以将 useMemo 的返回值定义为返回一个函数这样就可以变通的实现了 useCallback。在开发中当我们有部分变量改变时会影响到多个地方的更新那我们就可以返回一个对象或者数组,通过解构赋值的方式来实现同时对多个数据的缓存

const [age, followUser] = useMemo(() => {
  return [
    new Date().getFullYear() - userInfo.birth, // 根据生日计算年龄
    async () => { // 关注用户
      await request('/follow', { uid: userInfo.id });
      // ...
    }
  ];
}, [userInfo]);

return (
  <div>
    <span>name: {userInfo.name}</span>
    <span>age: {age}</span>
    <Card followUser={followUser}/>
    {
      useMemo(() => (
        // 如果 Card1 组件内部没有使用 React.memo 函数,那还可以通过这种方式在父组件减少子组件的渲染
        <Card1 followUser={followUser}/>
      ), [followUser])
    }
  </div>
)

useCallback

useCallback 的作用

官方文档:

Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.

简单来说就是返回一个函数,只有在依赖项发生变化的时候才会更新(返回一个新的函数)。 如果不使用useCallback时 ,每次更新状态 都会产生一个新的函数,将这个函数以props 传递给子组件则会导致不必要的更新,

juejin.cn/post/684490… 写的很好 推荐看