React中useCallback useMemo使用方法快速精通

 更新时间:2023年02月14日 16:53:31   作者:星海拾遗  
在React函数组件中,当组件中的props发生变化时,默认情况下整个组件都会重新渲染。换句话说,如果组件中的任何值更新,整个组件将重新渲染,包括没有更改values/props的函数/组件。在react中,我们可以通过memo,useMemo以及useCallback来防止子组件的rerender

首先从简单的讲一下两者的区别

useCallback和useMemo的区别

基本使用

	// 贴上代码片利于复制
	import { React, useState, useMemo, useCallback } from "react";
	export default function TestPage() {
	  const callBack = useCallback(() => {
	    console.log(1);
	  }, []);
	  const memo = useMemo(() => 123, []);
	  console.log("callback", callBack);
	  console.log("memo是", memo);
	  return (
	    <div>
	      <div>一个专门用于vue测试的页面</div>
	    </div>
	  );
}

控制台输出如下

可以直观的看到,useCallBack返回的是一个函数,useMemo返回的是一个变量。

接下来我们来剖析这两个东西的用法

useMemo

首先从简单的讲起,如果你学过Vue的话,完全可以把它当成Computed来理解。在这里举一个很好理解的

	import { React, useState, useMemo, useCallback } from "react";
	export default function TestPage() {
	  const [data, updateData] = useState(1);
	  const getComplicatedValue = () => {
	    console.log("开始计算一个复杂的value值啦!");
	    let total = 0;
	    for (let i = 0; i < 100; i++) {
	      total += i;
	    }
	    return total;
	  };
	  const changeData = () => {
	    updateData((oldValue) => oldValue + 1);
	  };
	  return (
	    <div>
	      <div>一个专门用于vue测试的页面</div>
	      <div>这是一个复杂函数计算出来的值{getComplicatedValue()}</div>
	      <div>这是一个简简单单的data值{data}</div>
	      <button onClick={changeData}>点击我改变data值</button>
	    </div>
	  );
	}

大意就是,页面上有一个很简单的值data,还有一个很复杂的经过函数计算出来的值getComplicatedValue,这里我用从1加到100来模拟了一个很复杂的计算过程(实际项目会更复杂)。

页面显示如下

显示正常,根据控制台显示也可以看到getComplicatedValue函数也被正常调用了。接下来我们点击按钮改变data的值。

可以看到页面是正常更新了的,但是性能问题出现了,我改变了data的值,导致render函数重新执行,然后getComplicatedValue又被执行了一遍!也就是计算机重新计算了1加到100。那么问题出现了,如果我是1加到100000呢?很显然,在我们更新data值的时候,并不需要getComplicatedValue再次执行,而是希望它的计算值被缓存起来。useMemo闪亮登场!!!当当当当。

改写如下,改写只需要改动两行

	import { React, useState, useMemo, useCallback } from "react";
	export default function TestPage() {
	  const [data, updateData] = useState(1);
	  const getComplicatedValue = useMemo(() => {
	    console.log("开始计算一个复杂的value值啦!");
	    let total = 0;
	    for (let i = 0; i < 100; i++) {
	      total += i;
	    }
	    return total;
	  },[]);
	  const changeData = () => {
	    updateData((oldValue) => oldValue + 1);
	  };
	  return (
	    <div>
	      <div>一个专门用于vue测试的页面</div>
	      <div>这是一个复杂函数计算出来的值{getComplicatedValue}</div>
	      <div>这是一个简简单单的data值{data}</div>
	      <button onClick={changeData}>点击我改变data值</button>
	    </div>
	  );
	}

第四行把getComplicatedValue函数用useMemo包裹起来。第18行删除(),因为刚刚已经说过,useMemo返回的是一个值而不是函数。

接下来再看看页面效果

这次可以看到,无论data值更新多少次,getComplicatedValue永远只执行了初始化的那一次。

来个首尾呼应

基本使用

const memo = useMemo(() => {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->},[依赖项数组])

如果依赖项数组里面的数据没有变化,那么memo值永远使用缓存,而不会重新计算

useCallback

useCallback比起useMemo就难上了一丢丢,因为涉及到了子组件。当然也是灰常简单。

首先来看一个简单

父组件

	import { React, useState, useMemo, useCallback } from "react";
	import TestSonComp from "./testSonComp";
	export default function TestPage() {
	  const [data, updateData] = useState(1);
	  const getValue = () => {
	    console.log("我是父组件的一个函数");
	  };
	  const changeData = () => {
	    updateData((oldValue) => oldValue + 1);
	  };
	  return (
	    <div>
	      <div>一个专门用于vue测试的页面</div>
	      <div>这是一个简简单单的data值{data}</div>
	      <button onClick={changeData}>点击我改变data值</button>
	      <TestSonComp getValue={getValue} />
	    </div>
	  );
}

子组件

	import { React, memo } from "react";
	const TestSonComp = (props) => {
	  console.log("子组件render函数执行了");
	  return <div>一个子组件</div>;
	};
	export default TestSonComp;

页面显示正常,然后点击按钮更新数据

那么此时问题又出现了,我就是在父组件中改了一下data值,data值导致父组件render重新执行,render生成了一个新的getValue函数,然后子组件props更新,导致子组件更新。那么有没有一个方法可以把函数缓存起来呢?

useCallback闪亮登场。

直接改写父组件定义函数的一行

	  const getValue = useCallback(() => {
	    console.log("我是父组件的一个函数");
	  }, []);

改完之后看页面效果你依然会发现和上图一样,子组件依然会更新!

问题出在这

useCallback必须配合React.memo来使用

react的Hooks组件对props的浅比较是在memo里面比较的(类组件是在shouldComponentUpdate里面),如果没有memo,那么你使用useCallback就没有意义

怎么使用?

子组件直接改写最后一行

export default memo(TestSonComp);

二话不说看效果

改写成功

再来个温故知新

基本使用

const callback = useCallback(() => {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->},[依赖项数组])

如果依赖项数组里面的数据没有变化,那么函数值也永远使用缓存。

到此这篇关于React中useCallback useMemo使用方法快速精通的文章就介绍到这了,更多相关React useCallback useMemo内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React合成事件原理解析

    React合成事件原理解析

    事件是在编程时系统内发生的动作或者发生的事情,而开发者可以某种方式对事件做出回应,而这里有几个先决条件,这篇文章主要介绍了React合成事件原理解析,需要的朋友可以参考下
    2022-07-07
  • react配置antd按需加载的使用

    react配置antd按需加载的使用

    这篇文章主要介绍了react配置antd按需加载的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • react-pdf实现将pdf文件转为图片,用于页面展示

    react-pdf实现将pdf文件转为图片,用于页面展示

    这篇文章主要介绍了react-pdf实现将pdf文件转为图片,用于页面展示问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • react-router-dom v6 使用详细示例

    react-router-dom v6 使用详细示例

    这篇文章主要介绍了react-router-dom v6使用详细示例,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-09-09
  • 详解react native页面间传递数据的几种方式

    详解react native页面间传递数据的几种方式

    这篇文章主要介绍了详解react native页面间传递数据的几种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • react dva实现的代码

    react dva实现的代码

    dva是一个基于redux和redux-saga的数据流方案,然后为了简化开发体验,dva额外内置了react-router,fetch,可以激烈为一个轻量级的应用框架,这篇文章主要介绍了react dva实现,需要的朋友可以参考下
    2021-11-11
  • 深入理解React调度(Scheduler)原理

    深入理解React调度(Scheduler)原理

    本文主要介绍了深入理解React调度(Scheduler)原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • React Native热重载时遇到的问题及解决过程

    React Native热重载时遇到的问题及解决过程

    热重载失效常见于文件类型不支持、配置错误、代码语法问题及状态/样式冲突,解决方法包括启用调试菜单、清除缓存、手动重启,优化项目体积,升级React Native版本,或改用FastRefresh提升兼容性与效率
    2025-09-09
  • 基于React-Dropzone开发上传组件功能(实例演示)

    基于React-Dropzone开发上传组件功能(实例演示)

    这篇文章主要介绍了基于React-Dropzone开发上传组件,主要讲述的是在React-Flask框架上开发上传组件的技巧,需要的朋友可以参考下
    2021-08-08
  • React 中如何将CSS visibility 属性设置为 hidden

    React 中如何将CSS visibility 属性设置为 hidden

    这篇文章主要介绍了React中如何将CSS visibility属性设置为 hidden,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05

最新评论