IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React中memo(),useMemo(),useCallback()的使用(区别,解决了什么问题) -> 正文阅读

[JavaScript知识库]React中memo(),useMemo(),useCallback()的使用(区别,解决了什么问题)

React中memo(),useMemo(),useCallback()的使用

前言:React框架中,当组件的props或state发生变化时,会重新渲染组件,实际开发中会遇到不必要的重新渲染场景。这里的memo(),useMemo(),useCallback()都是应用在函数组件中。调理不够清楚,希望你能够一步一步看。

React.memo()

React.memo()和类组件中React.PureComponent()很相似,它可以帮助我们控制什么时候重新渲染组件,它适用于函数组件,但不适用于 class 组件。如果你的函数组件在给定相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。
默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

下面看一个很简单的例子:

import React, { useState } from "react";
//子组件
const ChildCom = () => {
    console.log('render child component');
    return (
        <div>ChildComponent</div>
    )
};

//父组件
const ParaentCom = () => {
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    return (
        <div>
            <button onClick={increment}>点击加1</button>
            <div>点击次数:{count}</div>
            <ChildCom />
        </div>
    )
}
export default ParaentCom;

在这里插入图片描述

子组件中有console语句,在函数组件中,每次重新渲染都会重新打印输出。我们点击父组件中按钮,会修改count的值,进而导致父组件重新渲染,但是我们发现即使子组件的props和state没有变化,但控制台显示子组件也重新渲染了。但是我们这里期望的是:子组件的props和state没有变化时,即使父组件渲染,子组件也不需要重新渲染。

解决方法:使用React.memo()将子组件进行包裹

import React, { memo,useState } from "react";
//子组件
const ChildCom = memo(() => {
    console.log('render child component');
    return (
        <div>ChildComponent</div>
    )
});

//父组件
const ParaentCom = () => {
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    return (
        <div>
            <button onClick={increment}>点击加1</button>
            <div>点击次数:{count}</div>
            <ChildCom />
        </div>
    )
}
export default ParaentCom;

在这里插入图片描述
子组件使用React.memo包裹之后,我们多次点击按钮,发现子组件没有重新渲染。

React.useMemo()

上面的例子只是最简单的父组件没有向子组件传递props的情况,如果传递props时,我们怎么控制子组件不重复渲染或者只让某些props中的属性变化时子组件才重新渲染,这就需要用到 React.useMemo()。

useMemo 有两个参数:

  • 第一个参数是个函数,返回的对象指向同一个引用,不会创建新对象;
  • 第二个参数是个数组,只有数组中的变量改变时,第一个参数的函数才会返回一个新的对象。

看一个简单例子

import React, { memo,useState } from "react";
//子组件
const ChildCom = memo(({ number }) => {
    console.log('render child component', number);
    return (
        <div>ChildComponent</div>
    )
});

//父组件
const ParaentCom = () => {
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    return (
        <div>
            <button onClick={increment}>点击加1</button>
            <div>点击次数:{count}</div>
            <ChildCom number={count} />
        </div>
    )
}
export default ParaentCom;

在这里插入图片描述
如果props不改变,只使用memo()就可以控制子组件不重新渲染。上面是当传入props的值改变时,我们发现子组件进行了重新渲染,但是我们现在的期望是,即使props的值改变,子组件也不要重新渲染。

解决方法,看代码:

import React, { memo, useMemo,useState  } from "react";
//子组件
const ChildCom = memo(({ number }) => {
    console.log('render child component', number);
    return (
        <div>ChildComponent</div>
    )
});

//父组件
const ParaentCom = () => {
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    const number = useMemo(() => (count), []);
    return (
        <div>
            <button onClick={increment}>点击加1</button>
            <div>点击次数:{count}</div>
            <ChildCom number={number} />
        </div>
    )
}
export default ParaentCom;

在这里插入图片描述
发现即使子组件中props改变,子组件也没有进行重新渲染。

但是,下面一个期望是,控制props中的某些属性改变,也就是复杂的props,可以使子组件重新渲染,这里就需要useMemo的第二个参数来发挥作用了。

看代码:

import React, { memo, useMemo, useState } from "react";
//子组件
const ChildCom = memo(({ number }) => {
    console.log('render child component', number);
    return (
        <div>ChildComponent</div>
    )
});

//父组件
const ParaentCom = () => {
    const changeName = () => setName(name + 1);
    const changeAge = () => setAge(age + 1);
    const [name, setName] = useState('tom');
    const [age, setAge] = useState(20);
    const number = useMemo(() => ({ name, age }), [age]);
    return (
        <div>
            <button onClick={changeAge}>点击修改年龄</button>
            <button onClick={changeName}>点击修改姓名</button>
            <div>姓名:{name}  年龄:{age}</div>
            <ChildCom number={number} />
        </div>
    )
}
export default ParaentCom;

点击修改姓名时:
在这里插入图片描述
点击修改年龄时:
在这里插入图片描述
从上面两个截图中可以看出,可以这样理解,使用useMemo()方法监听age,从而让我们可以控制子组件什么时候进行重新渲染。但是props如果是方法的话,子组件依然会重新渲染,这里我们就需要useCallback()钩子。

React.useCallback()

先看一段代码:

import React, { memo, useState } from "react";
//子组件
const ChildCom = memo(() => {
    console.log('render child component');
    return (
        <div>ChildComponent</div>
    )
});

//父组件
const ParaentCom = () => {
    const [age, setAge] = useState(20);
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    const changeAge = () => setAge(age + 1);
    // const changeAge = useCallback(() => setAge(age + 1), [age])
    return (
        <div>
            <button onClick={increment}>点击加1</button>
            <div> 点击次数:{count}</div>
            <ChildCom onClick={changeAge} />
        </div>
    )
}
export default ParaentCom;

在这里插入图片描述

这里由于父组件重新渲染,导致传递的方法也重新渲染,也就是props又重新渲染了,所以子组件又重新渲染了。这种情况下,我们依然不想让子组件重新渲染。

解决方法

import React, { memo, useCallback, useState } from "react";
//子组件
const ChildCom = memo(() => {
    console.log('render child component');
    return (
        <div>ChildComponent</div>
    )
});

//父组件
const ParaentCom = () => {
    const [age, setAge] = useState(20);
    const [count, setCount] = useState(0);
    const increment = () => setCount(count + 1);
    const changeAge = useCallback(() => setAge(age + 1), [])
    return (
        <div>
            <button onClick={increment}>点击加1</button>
            <div> 点击次数:{count}</div>
            <ChildCom onClick={changeAge} />
        </div>
    )
}
export default ParaentCom;

在这里插入图片描述
此时点击父组件按钮,控制台就不会打印子组件被渲染的信息了。可以理解为:useCallback()起到了缓存的作用,即使父组件渲染了,useCallback()包裹的函数也不会重新生成,会返回上一次的函数引用。useCallback()钩子的第二个参数,和useMemo,useEffect用法都是一样的,这里就不多介绍。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 11:48:02  更:2022-05-10 11:48:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 21:47:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码