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

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

目录
相关文章
|
8月前
|
前端开发
轻松掌握 React Hooks:简化状态与副作用管理
轻松掌握 React Hooks:简化状态与副作用管理
257 80
|
8月前
|
前端开发
React Hooks数据获取:避免内存泄漏的实战指南
React Hooks数据获取:避免内存泄漏的实战指南
|
4月前
|
缓存 前端开发 JavaScript
React Hooks深度解析与最佳实践:提升函数组件能力的终极指南
🌟蒋星熠Jaxonic,前端探索者。专注React Hooks深度实践,从原理到实战,分享状态管理、性能优化与自定义Hook精髓。助力开发者掌握函数组件的无限可能,共赴技术星辰大海!
React Hooks深度解析与最佳实践:提升函数组件能力的终极指南
|
9月前
|
缓存 前端开发 Java
在 React 中,组合组件和高阶组件在性能方面有何区别?
在 React 中,组合组件和高阶组件在性能方面有何区别?
293 67
|
7月前
|
JavaScript 前端开发 API
对比Vue框架与React库的主要区别
在选择Vue还是React时,考虑项目的需求、团队的熟悉程度和个人偏好至关重要。如果项目需要快速原型开发和较小的学习曲线,Vue可能是更好的选择。相反,如果项目需要更大的灵活性,或者项目团队已经有React的经验,那么React可能是更合适的选择。
364 13
|
前端开发
React Hooks:从基础到进阶的深入理解
React Hooks:从基础到进阶的深入理解
319 2
|
前端开发 JavaScript
React Hooks 深入解析
React Hooks 深入解析
198 0
|
9月前
|
缓存 前端开发 数据安全/隐私保护
如何使用组合组件和高阶组件实现复杂的 React 应用程序?
如何使用组合组件和高阶组件实现复杂的 React 应用程序?
322 68
|
9月前
|
前端开发 JavaScript 安全
除了高阶组件和render props,还有哪些在 React 中实现代码复用的方法?
除了高阶组件和render props,还有哪些在 React 中实现代码复用的方法?
363 62
|
11月前
|
前端开发 JavaScript
除了使用Route组件,React Router还有其他方式处理404错误页面吗
除了使用Route组件,React Router还有其他方式处理404错误页面吗
303 58