2022-11-9 memo()和useMemo()和useCallback()的正确用法总结

91 阅读2分钟

Home.tsx

import React, { ReactElement, useCallback, useMemo, useState } from "react";
import Child from "../../components/Child";

interface HomeProps {}

const Home: React.FC<HomeProps> = ({}): ReactElement => {
  const [count, setCount] = useState(0);
  const [msg, setMsg] = useState("大内密探零零发");
  let personMsg = useMemo(() => {
    return {
      name: "张强",
    };
  }, []);
  const clickEvent = useCallback(() => {
    console.log("点击");
  }, []);

  return (
    <div>
      Home--{count}
      <div>
        <button onClick={() => setCount(count + 1)}>+</button>
      </div>
      <Child msg={msg} personMsg={personMsg} clickEvent={clickEvent} />
    </div>
  );
};

export default Home;

Child.tsx

import React, { memo } from "react";
interface ChildProps {
  msg: string;
  personMsg: any;
  clickEvent: ()=> void
}
const Child: React.FC<ChildProps> = memo(({ msg, personMsg, clickEvent }) => {
  console.log("ChildRender");
  return (
    <div>
      Child--{msg}
      <div>{personMsg.name}</div>
      <button onClick={clickEvent}>点击</button>
    </div>
  );
});
export default Child;

memo()用法:功能类似于class组件的PureComponent,帮助我们做SCU,即:子组件外层包裹memo()后,当父组件状态改变或者props改变的时候,如果子组件所依赖的属性没有发生改变,则子组件不发生re-render。只有父组件中和子组件相关依赖的属性发生改变的时候,子组件才会re-render.

useMemo()用法:必须和memo()结合使用。当父组件中存在一个变量(不是state)且传入子组件,每次父组件re-render的时候,这个变量都会重新构建,从而导致子组件的re-render。这个时候我们可以通过useMemo将变量进行包裹缓存,避免了变量的重新构建导致子组件的重新渲染。

useCallback()用法:必须和memo()结合使用。用法和useMemo()类似,区别是一个对变量进行缓存,一个对内部函数进行缓存。当父组件状态改变的时候,父组件的更新会重新构建其内部函数,如果某个内部函数传入了子组件,那么父组件函数的重新构建则会导致子组件的re-render。这时候则可以使用useCallback()将对应函数包裹,避免了函数的重新构建导致子组件的重新渲染。

useMemo()和useCallback()的第二个参数可以放入某些依赖,当这些依赖发生改变的时候才进行重新构建。

useMemo()还可以用作计算属性,防止组件re-render的时候进行重复的大量计算

个人总结:开发过程中,任何组件建议包裹memo()。传给子组件的变量(非state)用useMemo()包裹。传给子组件的函数用useCallback()包裹