【React】memo()、useCallback()、useMemo()的区别及使用场景

一、React.memo():用来控制函数组件的重新渲染,将组件作为参数,函数的返回值是一个新的组件。

import {
    useState} from "react";
const Child = () => {
   
  console.log("我是子组件", "渲染了");
  return <div>我是子组件</div>;
};
export const Parent = () => {
   
  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  return (
    <div>
      <button onClick={
   increment}>点击次数:{
   count}</button>
      <Child />
    </div>
  );
};

每点击一次,子组件的useState、props和context都没有改变,但是每点击一次子组件都会重新渲染

解决办法:将memo函数包裹子组件

import {
    memo } from "react";
const Child = memo(() => {
   
  console.log("我是子组件", "渲染了");
  return <div>我是子组件</div>;
});

二、React.useCallback():将回调函数及依赖项数组作为参数传入;

  • 它的主要作用是缓存一个回调函数,以确保在组件重新渲染时不会创建新的回调函数,从而减少不必要的性能开销。useCallback 通常与 React.memo 或 shouldComponentUpdate 一起使用,以避免不必要的组件重新渲染。
import {
    useState,memo } from "react";
const Child =  memo((props: {
     name: string; onClick: Function }) => {
   
  const {
    name, onClick } = props;
  console.log("我是子组件", "渲染了");
  return (
    <>
      <div>我是子组件={
   name}</div>
      <button onClick={
   () => onClick("修改父组件传过来的参数")}>改变 name 值</button>
    </>
  );
});
export const Parent = () => {
   
  const [count, setCount] = useState(0);
  const [name, setName] = useState("向子组件传递参数");
  const increment = () => setCount(count + 1);
  const onClick = (name: string) => {
   
    setName(name);
  };
  return (
    <div>
      <button onClick={
   increment}>点击次数:{
   count}</button>
      <Child name={
   name} onClick={
   onClick} />
    </div>
  );
};

每点击一次父组件的按钮,子组件都会重新渲染;

原因

  • 点击父组件按钮,父组件中 count 改变,进而导致父组件重新渲染;
  • 父组件重新渲染时,会重新创建 onClick 函数,即传给子组件的 onClick 属性发生了变化,导致子组件渲染;
  • 如果传给子组件的props只有[基本数据类型](https://blog.csdn.net/m0_61049675/article/details/135815841),子组件将不会重新渲染。

解决办法:修改父组件的 onClick 方法,用 useCallback 钩子函数包裹一层。
注意: 如果直接使用useState解构的setName传给子组件, 子组件将不会重复渲染,即使用<Child name={name} setName={setName} />

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

三、React.useMemo():将“创建”函数和依赖项数组作为参数传入;

import {
    useState,memo } from "react";
const Child =  memo((props: {
     userInfo: {
     name: string; age: number } }) => {
   
  const {
    userInfo} = props;
  console.log("我是子组件", "渲染了");
  return (
    <>
      <div>我是子组件={
   userInfo}</div>
      <button>改变 name 值</button>
    </>
  );
});
export const Parent = () => {
   
  const [count, setCount] = useState(0);
  const userInfo = ({
    name: "小明", age: 18 });
  const increment = () => setCount(count + 1);
  return (
    <div>
      <button onClick={
   increment}>点击次数:{
   count}</button>
      <Child userInfo={
   userInfo}/>
    </div>
  );
};

每点击一次父组件的按钮,子组件都会重新渲染;

原因

  • 点击父组件按钮,父组件重新渲染;
  • 父组件重新渲染时,会重新生成一个新对象userInfo ,即传给子组件的 userInfo 属性发生了变化,导致子组件渲染;
    解决办法:使用 useMemo 将对象属性包一层。
    注意: 如果直接使用useState解构的userInfo, 子组件将不会重复渲染,即使用const [userInfo, setUserInfo] = useState({ name: "小明", age: 18 });
const userInfo = useMemo(() => ({
    name: "小明", age: 18 }), []);

四、结论

  • useMemo返回的是一个变量的值,useCallback返回的是一个函数。
  • useMemo就是作为一个值来使用的,而useCallback则是被绑定的onClick,作为要执行的函数。
  • useCallback和useMemo主要用来做数据缓存,它们的更新依赖于第二个参数是否发生了变化。因此当我们的render重复渲染时,只要我们的useMemo和useCallback的第二个参数值没有发生变化,useMemo和useCallback则不会执行第一个参数里的函数。
  • 当父组件重新发生render的时候,子组件接受父组件的自定义方法,如果我不希望子组件发生变化,那么就需要用useCallback包裹父组件的自定义函数;

相关推荐

  1. CSS中px、em、rem区别使用场景

    2024-02-02 13:52:03       20 阅读
  2. C/C++ 引用和指针区别使用场景

    2024-02-02 13:52:03       8 阅读
  3. 区块应用场景优势

    2024-02-02 13:52:03       13 阅读
  4. 深入剖析OR与UNION区别应用场景

    2024-02-02 13:52:03       13 阅读
  5. Redis 数据类型使用场景

    2024-02-02 13:52:03       18 阅读
  6. TensorFlow基本概念使用场景

    2024-02-02 13:52:03       14 阅读
  7. PyTorch基本概念使用场景

    2024-02-02 13:52:03       13 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-02 13:52:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-02 13:52:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-02 13:52:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-02 13:52:03       18 阅读

热门阅读

  1. Android 禁用字体随系统大小变化

    2024-02-02 13:52:03       38 阅读
  2. 【大模型】websocket连接频繁断掉的问题

    2024-02-02 13:52:03       49 阅读
  3. week03day04(正则表达式2)

    2024-02-02 13:52:03       26 阅读
  4. word使用技巧

    2024-02-02 13:52:03       30 阅读
  5. C++——虚继承与菱形继承

    2024-02-02 13:52:03       32 阅读
  6. MySQL的存储格式,MySQL的触发器

    2024-02-02 13:52:03       34 阅读
  7. 【学习心得】Django框架自带的密码加解密方法

    2024-02-02 13:52:03       29 阅读