React中函数式Hooks之memo、useCallback的使用以及useMemo、useCallback的区别

简介: React中的`memo`是高阶组件,类似于类组件的`PureComponent`,用于避免不必要的渲染。`useCallback` Hook 用于缓存函数,避免在每次渲染时都创建新的函数实例。`memo`可以接收一个比较函数作为第二个参数,以确定是否需要重新渲染组件。`useMemo`用于缓存计算结果,避免重复计算。两者都可以用来优化性能,但适用场景不同:`memo`用于组件,`useMemo`和`useCallback`用于值和函数的缓存。

昨天学习了useMemo的使用,我们知道useMemo起到了缓存变量的作用。
而useCallback的作用起到了缓存函数的作用。下面我们来看一下怎么使用以及注意事项。

memo

首先我们先来学习一下memo这个函数,这个函数是从react中直接使用的这个函数是一个包裹函数;

import React, {
     memo } from 'react'

它的作用类似class组件中的pureComponent;以及shouldComponentUpdate这个钩子函数的作用。

在function时代,已经没有了pureComponent和shouldComponentUpdate这种东西,而是react提供了React.memo这样的高阶组件,与pureComponent和相似,但是,这个高阶组件并不是适用于class组件,而只为function组件服务。相比于 PureComponent ,React.memo() 可以支持指定一个参数,可以相当于 shouldComponentUpdate 的作用,因此 React.memo() 相对于 PureComponent 来说,用法更加方便。

用法:

const A = memo(function A(props) {
   
  let {
    giveSonFun } = props
  console.log(giveSonFun, 'giveSonFun')
  return (
    <>
      我是A组件内容
    </>
  )
})
export default A;

这样一来我们的组件就会自动的根据变量是否变化而从新渲染函数式组件;

当我们将A组件作为子组件的时候,无论父组件谁的状态更新了,它的所有子组件都会自动的进行重新渲染,有时候我们的子组件是完全没有必要重新渲染的,所有我们可以使用这个React.mome组件进行包裹,起到了纯组件(pureComponent)的作用。

useCallback

首先我们看下面的例子,我们用到了useState这个hook:

import './App.css';
import React, {
    useState, useMemo,  useCallback, memo } from 'react'
function App() {
   
  const [name, setName] = useState("LiuQing")
 const a =1
  // 类似vue 中的computed 计算属性  
  // 用于缓存变量
  const studyRun = React.useMemo(() => name + 'String', [name])
  const changeName = () => {
   
    setName("mynameiszjq" + Math.random())
  }
 // const giveSonFun = useCallback(() => {
   
 //   console.log("子组件执行了函数")
//  }, [a])

  const giveSonFun = () => {
   
     console.log("子组件执行了函数")
   }

  return (
    <React.Fragment>
      <p>studyRun:{
   studyRun}</p>
      <button onClick={
   changeName}>点击更改studyRun</button>
      <div style={
   {
    border: "2px solid #ccc", height: "300px", width: "500px" }}>
        我是A组件
      <A giveSonFun={
   giveSonFun} />
      </div>
    </React.Fragment>
  );
}

const A = memo(function A(props) {
   
  let {
    giveSonFun } = props
  console.log(giveSonFun, 'giveSonFun')
  return (
    <>
      我是A组件内容
        <hr />
      <button onClick={
   giveSonFun}>点击我执行父组件传入的方法</button>
    </>
  )
})


export default App;

在上面的例子中我们在APP组件中写个两个giveSonFun 方法,一个是用useCallback包裹的,一个是普通的函数,
我们先使用普通函数,看效果。
在这里插入图片描述
页面初始化的时候,打印了一个giveSonFun 函数体,说明我们子组件渲染了一次。
我们开始点击,APP组件中的按钮:
在这里插入图片描述
我们点击了几次,子组件A重新render了几次,说明每一次都传入了一个新的函数地址。

我们打开useCallback包裹的函数giveSonFun ,注释掉普通函数giveSonFun ;

import './App.css';
import React, {
    useState, useMemo,  useCallback, memo } from 'react'
function App() {
   
  const [name, setName] = useState("LiuQing")
   const a =1
  // 类似vue 中的computed 计算属性  
  // 用于缓存变量
  const studyRun = React.useMemo(() => name + 'String', [name])
  const changeName = () => {
   
    setName("mynameiszjq" + Math.random())
  }
  const giveSonFun = useCallback(() => {
   
    console.log("子组件执行了函数")
  }, [a])

  // const giveSonFun = () => {
   
  //   console.log("子组件执行了函数")
  // }

  return (
    <React.Fragment>
      <p>studyRun:{
   studyRun}</p>
      <button onClick={
   changeName}>点击更改studyRun</button>
      <div style={
   {
    border: "2px solid #ccc", height: "300px", width: "500px" }}>
        我是A组件
      <A giveSonFun={
   giveSonFun} />
      </div>
    </React.Fragment>
  );
}

const A = memo(function A(props) {
   
  let {
    giveSonFun } = props
  console.log(giveSonFun, 'giveSonFun')
  return (
    <>
      我是A组件内容
        <hr />
      <button onClick={
   giveSonFun}>点击我执行父组件传入的方法</button>
    </>
  )
})


export default App;

同样的页面初始话的时候,A组件渲染了一次:
在这里插入图片描述
但是后面我们点击APP函数中的按钮,打印台并没有重新打印函数体;
在这里插入图片描述
后面的随机数变化表示我们最少点击了一次,控制台还是没有打印函数体。
所以我们使用useCallback实现了缓存函数的效果。

我们不难发现,useCallback有两个参数:
第一个参数是一个函数体;
第二个参数是一个数组;
其实第二个参数和useEffect的效果一样;
当我们不传入第二个参数的时候,所有的状态改变都会触发useCallback重新返回一个新的缓存函数;
当我们你传入一个空数组的时候,所有状态的改变都不会触发useCallback重新返回一个新的缓存函数;
当我们传入一个数组,并且数组中有变量的时候,只有这个变量状态改变才会触发useCallback重新返回一个新的缓存函数;

我们上边的例子使用了一个变量a作为useCallback返回新缓存函数的条件,事实上我们的a一直没有变;
当我们将a换成 name后,这个缓存函数会根据name变量改变与否来返回新缓存函数与否;

import './App.css';
import React, {
    useState, useMemo,  useCallback, memo } from 'react'
function App() {
   
  const [name, setName] = useState("LiuQing")
  // 类似vue 中的computed 计算属性  
  // 用于缓存变量
  const studyRun = React.useMemo(() => name + 'String', [name])
  const changeName = () => {
   
    setName("mynameiszjq" + Math.random())
  }
  const giveSonFun = useCallback(() => {
   
    console.log("子组件执行了函数")
  }, [name])


  return (
    <React.Fragment>
      <p>studyRun:{
   studyRun}</p>
      <button onClick={
   changeName}>点击更改studyRun</button>
      <div style={
   {
    border: "2px solid #ccc", height: "300px", width: "500px" }}>
        我是A组件
      <A giveSonFun={
   giveSonFun} />
      </div>
    </React.Fragment>
  );
}

const A = memo(function A(props) {
   
  let {
    giveSonFun } = props
  console.log(giveSonFun, 'giveSonFun')
  return (
    <>
      我是A组件内容
        <hr />
      <button onClick={
   giveSonFun}>点击我执行父组件传入的方法</button>
    </>
  )
})


export default App;

在这里插入图片描述
每点击一次name的值都会被重新set,所有每次传入子组件都是一个新的giveSonFun 函数,所有A组件会从新渲染。

总结:
memo:为了像纯组件一样,根据变量前后状态来判断更新组件与否;
useMemo:缓存变量;
useCallback:缓存函数;
在这里插入图片描述
附参考地址:https://blog.csdn.net/leelxp/article/details/107822103

革命尚未完成,同志还需努力

目录
相关文章
|
2天前
|
前端开发
React中函数式Hooks之useEffect的使用
本文通过示例代码讲解了React中`useEffect` Hook的用法,包括模拟生命周期、监听状态和清理资源。
10 2
React中函数式Hooks之useEffect的使用
|
2天前
|
前端开发 JavaScript
React_函数式Hooks和Class比较优缺点
React Hooks与Class组件都能返回JSX并接收props,但Hooks无`this`指向问题,用`useEffect`模拟生命周期,`memo`优化性能,状态更新用`useState`;Class组件通过生命周期方法、`PureComponent`或`shouldComponentUpdate`优化,状态用`this.state`和`this.setState`管理。
10 1
React_函数式Hooks和Class比较优缺点
|
2天前
|
前端开发 JavaScript
React中函数式Hooks之useRef的使用
React中函数式Hooks的useRef用于获取DOM元素的引用,示例代码演示了其基本用法。
12 3
|
2天前
|
前端开发
React使用hooks遇到的坑_state中的某几个属性数据变成了空字符
本文讨论了在React使用hooks时遇到的一个问题:state中的某些属性数据变成了空字符。作者通过在修改函数中重新解构赋值来获取最新的state值,解决了因数据更新不及时导致的问题。
7 0
|
2天前
|
缓存 前端开发
React中函数式Hooks之useMemo的使用
React的`useMemo` Hook 用于优化性能,通过记忆返回值避免重复计算。它接收一个函数和一个依赖数组,只有当依赖项改变时,才会重新计算被记忆的值。这可以用于避免在每次渲染时都进行昂贵的计算,或者防止子组件不必要的重新渲染。例如,可以在父组件中使用`useMemo`包裹子组件,以依赖特定的props,从而控制子组件的渲染。
9 0
|
1月前
|
前端开发 JavaScript UED
React 基础与实践 | 青训营笔记
React 基础与实践 | 青训营笔记
41 0
|
2月前
|
前端开发 JavaScript Java
React 速通笔记
【7月更文挑战第17天】
36 1
|
前端开发
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
70 0
|
前端开发
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之8
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之7
47 0
|
4月前
|
前端开发 JavaScript
前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件
前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件
57 1