React 正确使用useCallback useMemo的姿势
正确使用useCallback useMemo的姿势
说起useCallback useMemo大家肯定在React都不陌生,但是真正了解它们的作用,还是有一部分同学对此是一知半解,只是知道用它,却不知道它真正的含义。 今天带大家学习一下它们的真正蕴藏的作用。 useCallback useMemo 都是记忆函数,什么是记忆函数呢? 用个最简单的例子来讲 useState 也是记忆函数 细想一下以下代码,为什么setcount每次改变会引起组件重新render,但是count为什么不会再次被初始值0进行赋值呢? 如果是这样的话,我们就不能修改成功了,所以说存在某个地方保存了state的值,而这个地方是不会受到render的影响的,state就被缓存起来了。
const [count, setcount] = useState(0);
那么 useCallback useMemo 也是被缓存起来了吗?让我们逐个来看看
useCallback
useCallback 的作用是啥?我们来看看下面的代码
import React, { memo, useCallback, useState } from "react";
const HookTest = memo(() => {
const [count, setcount] = useState(0);
const [num, setnum] = useState(100);
const showCount = () => {
console.log("没事执行玩玩", count + "$");
};
return (
<div>
<h2>HookTest:useCallback----useMemo</h2>
<h3>useCallBack</h3>
<h4>
count:{count}---num:{num}
</h4>
<button onClick={showCount}>showCount</button>
<button onClick={(e) => setcount(count + 3)}>+3</button>
<button onClick={(e) => setnum(num * 10)}>*10</button>
);
});
export default HookTest;
正常执行的话,修改count 和 num 都会触发 render ,这是毫无疑问的。那么showCount 每次render也会被重新创建一次,这也是情理之中的。 但是我们想想,真的有必要每次render都重新创建showCount 吗?现在可能只有一个函数,函数体也简单,重新创建也影响不了什么,但是真正开发的时候却是我们要考虑的问题。 所以 useCallback 来帮我们解决这个问题了!
const showCount = () => {
console.log("没事执行玩玩", count + "$");
};
const showCount = useCallback(() => {
console.log("没事执行玩玩", count + "$");
}, [count]);
useCallback 接收两个参数 第一个为需要缓存的函数 第二个为数组,装载依赖
那么现在的 showCount 和之前的又有什么不一样呢? 现在的 showCount 是被缓存起来了,组件render时,如果装载依赖的数组中的依赖未更新,那么依然采用缓存的函数。 也就是说只有当我点修改count时触发更新组件render后,showCount 也重新创建,但是当我进行其他的操作引起组件render时,由于此时条件依赖跟装载依赖的数组中依赖毫无关系,showCount 用的是缓存里的函数。 这就是 useCallback 的正确使用方法啦~
useMemo
看下面案例
import React, { memo, useMemo, useState } from "react";
const HookTest = memo(() => {
const [count, setcount] = useState(0);
const [arr, setarr] = useState([
{
flag: true,
num: 20,
},
{
flag: false,
num: 10,
},
{
flag: true,
num: 40,
},
{
flag: true,
num: 60,
},
{
flag: true,
num: 70,
},
{
flag: true,
num: 80,
},
]);
const allNum = () =>
arr.reduce(
(preValue, currentValue) =>
currentValue.flag ? preValue + currentValue.num : preValue,
0
);
return (
<div>
<h2>HookTest:useCallback----useMemo</h2>
<h3>useMemo</h3>
<h4>
count:{count}
</h4>
<button onClick={(e) => setcount(count + 3)}>+3</button>
<h4>all:{allNum}</h4>
</div>
);
});
export default HookTest;
很简单的小案例,根据条件对数组求和操作 同样我们点击修改count 然后组件重新render 此时我们考虑一个问题,是不是 allNum 又进行了一次复杂的运行然后得到结果? 现在看来才几条数据,怎么复杂了,我们得考虑数组若是几百上千上万呢? 我们都知道组件渲染是很频繁的,那么每次渲染我们真的有必要去每次进行复杂的运算吗? 所以这就是性能优化的另一个点了 引出 useMemo来帮助我们解决
将allNum 改造后
const allNum = () =>
arr.reduce(
(preValue, currentValue) =>
currentValue.flag ? preValue + currentValue.num : preValue,
0
);
const allNum = useMemo(
() =>
arr.reduce(
(preValue, currentValue) =>
currentValue.flag ? preValue + currentValue.num : preValue,
0
),
[arr]
);
useMemo 同样接收两个参数 第一个参数是函数,要求这个函数必须有返回值!! 第二个为数组,装载依赖 用了之后呢?有那些改变呢? 现在 allNum 不再是一个函数了,而是一个返回值 现在如果进行和依赖数组无关的render时,allNum 将采用上次缓存的返回值,不用再去傻傻的计算一遍啦。
这就是 useMemo 的正确使用方法啦~
总结
简单给大家总结下 useCallback 缓存函数 useMemo 缓存函数返回值 都是解决组件频繁渲染从而频繁创建函数及频繁运行函数 正确的思路应该是 跟我有关的时候我才需要去重新创建函数及重新运行函数 跟我无关的时候,直接拿上一次的缓存结果就行啦!
求赞!!!
转载自:https://juejin.cn/post/7128664391393738789