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_hooks系列03_useCallback,高阶函数memo -> 正文阅读

[JavaScript知识库]react_hooks系列03_useCallback,高阶函数memo

react_hooks的useCallback,高阶函数memo

一、概念和作用

1、memo高阶函数:

memo解决的是函数式组件的无效渲染问题,当函数式组件重新渲染时,会先判断数据是否发生了变化。相当于类组件的PureComponent(默认提供ShouldComponentUpdate)

2、useCallback:

1)、useCallback会返回一个函数的memoized(记忆的)值

2)、在依赖不变的情况下,多次定义(如:函数)的时候,返回的值是相同的 。

3)、格式:

let 新的函数 = useCallback(曾经的函数, [依赖的值]) 

二、使用场景:

1、memo高阶函数的使用场景:

不论父组件是什么类型的组件,子组件是否渲染 :

1)、 如果子组件是类组件(继承自PureComponent)

? 那么是否渲染由props和state是否改变决定;

2)、如果子组件是函数式组件

? 只要父组件渲染,子组件会无条件渲染。如下是代码示例:

//父组件:

import { useState } from "react";
import SonFn from "./SonFn";

export default () => {
    console.log("父组件");
    const [count, setCount] = useState(1);

    let changeCount = () => {
        setCount(count + 1);
    }

    return (
        <>
            <h1>useCallback</h1>
            <p>{count}</p>
            <input type="button" value="修改count" onClick={changeCount} />
            <hr />
            <SonFn />
        </>
    )
}

//子组件:
./SonFn.js

export default ()=>{
    console.log("子组件");
    return (
        <div>
            <h5>子组件(函数式组件)</h5>
        </div>
    )
}   

只要点击按钮"修改count”,父组件就会刷新,而子组件SonFn也会无条件渲染(这是无效的渲染)。

3)、解决方案:

? 把子组件用高阶函数memo进行包裹,就能解决子组件的无条件渲染问题,即:子组件的渲染就会由props和state决定,有点像类组件继承自PureComponent的感觉。

如下是代码(只需要把子组件的代码进行修改就行):

//子组件:
import React,{memo} from 'react'

const SonFn = ()=>{
    console.log("子组件");
    return (
        <div>
            <h5>子组件(函数式组件)</h5>
        </div>
    )
}

export default memo(SonFn);
2、useCallback的使用场景:

父组件是函数式组件,子组件也是函数式组件(并且用memo包裹)

1)、子组件的属性是数据:

? 如果数据不变化,那么子组件不渲染,如果数据发生变化,那么子组件渲染。这里就没有性能问题。

//父组件

import { useState,useCallback } from "react";
import SonFn from "./SonFn";

export default () => {
    console.log("父组件UseCallback");
    const [count, setCount] = useState(1);

    let changeCount = () => {
        setCount(count + 1);
    }

    return (
        <>
            <h1>useCallback1</h1>
            <p>{count}</p>
            <input type="button" value="修改count" onClick={changeCount} />
            <hr/>
        	{/*此处给子组件传入了数据count,count只要发生变化,子组件就会重新渲染*/}
            <SonFn count={count} />
        </>
    )
}

//子组件:
./SonFn.js

import React,{memo} from 'react'

const SonFn = ({count})=>{
    console.log("子组件");
    return (
        <div>
            <h5>子组件(函数式组件)</h5>
            <p>{count}</p>
        </div>
    )
}

export default memo(SonFn);


2)、子组件的属性是函数时,就会出现问题:

? 父组件刷新了,子组件依然会刷新。因为,父组件(函数式)每次刷新时,函数都会重新定义,那么传给子组件的函数属性必然会发生变化。所以子组件会刷新,如下是示例代码:

//父组件:

import { useState } from "react";
import SonFn from "./SonFn";

export default () => {
    console.log("父组件");
    const [count, setCount] = useState(1);

    let changeCount = () => {
        setCount(count + 1);
    }

    let increment = ()=>{
        console.log("increment");
    }

    return (
        <>
            <h1>useCallback</h1>
            <p>{count}</p>
            <input type="button" value="修改count" onClick={changeCount} />
            <hr/>
            <SonFn onMyClick={increment} />
        </>
    )
}

//子组件:
./SonFn.js

import React,{memo} from 'react'

const SonFn = ()=>{
    console.log("子组件");
    return (
        <div>
            <h5>子组件(函数式组件)</h5>
        </div>
    )
}

export default memo(SonFn);

3)、解决方案:把传给子组件的函数属性,用useCallback包裹。

格式:

let 新的函数 = useCallback(曾经的函数, [依赖的值]) 

如下是修改后的代码(只需要修改父组件的代码):

以下代码把increment函数进行了包裹

export default () => {
    console.log("父组件");
    const [count, setCount] = useState(1);

    let changeCount = () => {
        setCount(count + 1);
    }

    let increment = useCallback(()=>{
        console.log("increment");
    },[]) // 该函数永远不会重新定义(没有依赖)
    
    /*
    let increment = useCallback(()=>{
        console.log("increment");
    },[count]) // 当count的值发生变化是,该函数才会重新定义
	*/
    
    return (
        <>
            <h1>useCallback</h1>
            <p>{count}</p>
            <input type="button" value="修改count" onClick={changeCount} />
            <hr/>
            <SonFn onMyClick={increment} />
        </>
    )
}

三、总结:

1、“万恶之源” :函数式组件每次重新渲染时,都会把函数体里的所有代码执行一遍。

2、useCallback解决的是 防止函数式组件里的 子函数(闭包) 多次被定义。既就是:useCallback是保证函数式组件重新渲染时,组件里的函数(闭包)只被定义一次

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:10:38  更:2021-11-28 11:10:46 
 
开发: 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 6:25:50-

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