React中memo useCallback useMemo方法作用及使用场景

 更新时间:2023年03月05日 15:04:53   作者:Jiaynn  
这篇文章主要为大家介绍了React中三个hooks方法memo useCallback useMemo的作用及使用场景示例,有需要的朋友可以借鉴参考下,希望能够有所帮助

memo()、useCallback()、useMemo()使用场景

当父组件的props或state变化时,render重新渲染,但传递给子组件的props没有发生变化说着只是简单调用了一下子组件,这时子组件也要重新渲染,这就导致了组件的不必要的渲染

React.memo()

当父组件只是简单调用子组件,并未给子组件传递任何属性,我们可以通过memo来控制函数组件的渲染

React.memo()将组件作为函数(memo)的参数,函数的返回值(Child)是一个新的组件。

import { useState } from "react";
import { Child } from "./child";
export const Parent = () => {
  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  return (
    <div>
      <button onClick={increment}>点击次数:{count}</button>
      <Child />
    </div>
  );
};
import {memo} from 'react'
export const Child=memo(()=>{
    consloe.log('渲染了')
    return <div>子组件</div>
})
//使用memo()包裹后的组件,在Parent组件重新渲染更新时,Child组件并没有重新渲染更新

当我们传值给子组件时,这时使用memo函数就对控制组件的更新不起作用了

父组件

import { useState } from "react";
import { Child } from "./child";
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>
  );
};

子组件

import { memo } from "react";
export const Child = memo(
  (props: { name: string; onClick: (value: any) => void }) => {
    const { name, onClick } = props;
    console.log("渲染了", name, onClick);
    return (
      <>
        <div>子组件</div>
        <button onClick={() => onClick("小红")}>改变 name 值</button>
      </>
    );
  }
);

出现这样结果的原因:

点击父组件按钮时,改变了父组件的count,导致父组件重新渲染

父组件重新渲染时,重新创建了onClick函数,导致传递给子组件的onClick属性发生了变化,导致子组件重新渲染

如果传递给子组件的只有基本数据类型将不会重新渲染

注意: 如果直接使用useState解构的setName传给子组件, 子组件将不会重复渲染,因为解构出来的是一个memoized 函数。

React.useCallback()

所以,在这种情况下我们使用React.useCallback() useCallback(fn, deps)

import { useCallback, useState } from "react";
import { Child } from "./child";
export const Parent = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("小明");
  const increment = () => setCount(count + 1);
//使用useCallback钩子包裹的回调函数是memoized函数,他初次调用该函数时,缓存参数和计算结果,再次调用这个函数时,如果第二个参数依赖项没有发生改变,则直接返回缓存结果,不会重新渲染
  const onClick = useCallback((name: string) => {
    setName(name);
  }, []);
  return (
    <div>
      <button onClick={increment}>点击次数:{count}</button>
      <Child name={name} onClick={onClick} />
    </div>
  );
};

但当我们传递的属性name不字符串,而是对象时

父组件

import { useCallback, useState } from "react";
import { Child } from "./child";
export const Parent = () => {
  const [count, setCount] = useState(0);
  // const [userInfo, setUserInfo] = useState({ name: "小明", age: 18 });
  const increment = () => setCount(count + 1);
  const userInfo = { name: "小明", age: 18 };
  return (
    <div>
      <button onClick={increment}>点击次数:{count}</button>
      <Child userInfo={userInfo} />
    </div>
  );
};

子组件

import { memo } from "react";
export const Child = memo(
  (props: { userInfo: { name: string; age: number } }) => {
    const { userInfo } = props;
    console.log("渲染了", userInfo);
    return (
      <>
        <div>名字: {userInfo.name}</div>
        <div>年龄:{userInfo.age}</div>
      </>
    );
  }
);

点击父组件count,看到子组件每次都重新渲染了。 分析原因跟调用函数是一样的:

  • 点击父组件按钮,触发父组件重新渲染;
  • 父组件渲染,const userInfo = { name: "小明", age: 18 }; 一行会重新生成一个新对象,导致传递给子组件的 userInfo 属性值变化,进而导致子组件重新渲染。
  • 注意: 如果使用useState解构的userInfo, 子组件将不会重复渲染,因为解构出来的是一个memoized 值。

这时我们使用 React.useMemo() useMemo(() => fn, dep)

React.useMemo()

useMemo()返回的是一个 memoized 值。

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

import { useMemo, useState } from "react";
import { Child } from "./child";
export const Parent = () => {
  const [count, setCount] = useState(0);
  // const [userInfo, setUserInfo] = useState({ name: "小明", age: 18 });
  const increment = () => setCount(count + 1);
  const userInfo = useMemo(() => ({ name: "小明", age: 18 }), []);
  return (
    <div>
      <button onClick={increment}>点击次数:{count}</button>
      <Child userInfo={userInfo} />
    </div>
  );
};

对比useCallback() 和useMemo()

useCallback(fn, deps) 返回该回调函数的memoized回调函数

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

useMemo(() => fn, dep) 返回的是一个 memoized 值。

const userInfo = useMemo(() => ({ name: "小明", age: 18 }), []);

以上就是React中memo useCallback useMemo方法作用及使用场景的详细内容,更多关于React useCallback useMemo的资料请关注脚本之家其它相关文章!

相关文章

  • react实现antd线上主题动态切换功能

    react实现antd线上主题动态切换功能

    这篇文章主要介绍了react实现antd线上主题动态切换功能,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • 详解React 的数据流和生命周期

    详解React 的数据流和生命周期

    这篇文章主要介绍了React 的数据流和生命周期,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • React高级特性Context万字详细解读

    React高级特性Context万字详细解读

    React的context就是一个全局变量,可以从根组件跨级别在React的组件中传递。React context的API有两个版本,React16.x之前的是老版本的context,之后的是新版本的context
    2022-11-11
  • create-react-app使用antd按需加载的样式无效问题的解决

    create-react-app使用antd按需加载的样式无效问题的解决

    这篇文章主要介绍了create-react-app使用antd按需加载的样式无效问题的解决,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • react虚拟列表实现及原理小结

    react虚拟列表实现及原理小结

    React虚拟列表是前端性能优化的核心技术之一,尤其在需要渲染上万条数据的表格或列表时很关键,下面就来介绍一下react虚拟列表的实现,感兴趣的可以了解一下
    2025-09-09
  • React实现随机颜色选择器的示例代码

    React实现随机颜色选择器的示例代码

    颜色选择器是一个用于选择和调整颜色的工具,它可以让用户选择他们喜欢的颜色,本文主要介绍了React实现随机颜色选择器的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • React中实现组件通信的几种方式小结

    React中实现组件通信的几种方式小结

    在构建复杂的React应用时,组件之间的通信是至关重要的,从简单的父子组件通信到跨组件状态同步,不同组件之间的通信方式多种多样,下面我们认识react组件通信的几种方式,需要的朋友可以参考下
    2024-04-04
  • ReactJs快速入门教程(精华版)

    ReactJs快速入门教程(精华版)

    React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站.这篇文章主要介绍了ReactJs快速入门教程(精华版)的相关资料,需要的朋友可以参考下
    2016-11-11
  • React实践之Tree组件的使用方法

    React实践之Tree组件的使用方法

    本篇文章主要介绍了React实践之Tree组件的使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • react以create-react-app为基础创建项目

    react以create-react-app为基础创建项目

    这篇文章主要介绍了react以create-react-app为基础创建项目,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03

最新评论