useCallback:在组件中定义事件回调或者是某些函数处理时选择使用
useMemo(memory记忆):根据已有状态计算某些数据并且计算过程较消耗性能时选择使用
下面直接demo演示,还是components下新建一个CallbackMemoDemo.js并在App.js中将其引入:
import React from 'react';
export default function CallbackMemoDemo() {
return <div>
CallbackMemoDemo
</div>
}
...
import CallbackMemoDemo from "./components/CallbackMemoDemo";
function App() {
...
return (
<div>
...
<CallbackMemoDemo />
</div>
);
}
export default App;
选择假如有个定时器:
import React, { useEffect, useState } from 'react';
export default function CallbackMemoDemo() {
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
}, 1000);
},[]);
console.log("updating...");
const handleClick = () => console.log("CallbackMemoDemo click");
return <div onClick={handleClick}>
{count}
</div>
}
可以发现每次count变化时,页面都会重新渲染,这个handleClick也会重新被定义,这样就造成不必要的开销,实际handleClick只用定义一次就行:
import React, { useCallback, useEffect, useState } from 'react';
export default function CallbackMemoDemo() {
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
}, 1000);
},[]);
console.log("updating...");
const handleClick = useCallback(() => console.log("CallbackMemoDemo click:", count), []);
return <div onClick={handleClick}>
{count}
</div>
}
计时的过程中点击变动的数字,页面的count都计时到20了,而handleclick的count还是初始值0,说明只定义了一次:
现在如果有一个result需要根据count计算,假设它只根据count的变化而计算,而且计算一次比较费时:
import React, { useCallback, useEffect, useState } from 'react';
export default function CallbackMemoDemo() {
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
}, 1000);
},[]);
const result = count * 100;
const handleClick = useCallback(() => console.log("CallbackMemoDemo click:", count), []);
return <div onClick={handleClick}>
{count}--{result}
</div>
}
如果这样写,混杂着其它变化更快的状态,那么result的计算次数也被带偏:
import React, { useCallback, useEffect, useState } from 'react';
export default function CallbackMemoDemo() {
const [count, setCount] = useState(0);
const [otherCount, setOtherCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
console.log("count changing");
}, 1000);
setInterval(() => {
setOtherCount(otherCount => otherCount + 1);
}, 300);
},[]);
const result = count * 100;
console.log("result calculating");
const handleClick = useCallback(() => console.log("CallbackMemoDemo click:", count), []);
return <div onClick={handleClick}>
{otherCount}--{count}--{result}
</div>
}
result calculating应该和count changing五五开才对,这样被otherCount带着快速计算,如果result本身计算很费时间,那么app的性能就下降得很快,太多资源给了result重复计算。
所以这时候就用到useMemo:
import React, { useCallback, useEffect, useMemo, useState } from 'react';
export default function CallbackMemoDemo() {
const [count, setCount] = useState(0);
const [otherCount, setOtherCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
console.log("count changing");
}, 1000);
setInterval(() => {
setOtherCount(otherCount => otherCount + 1);
}, 300);
},[]);
const result = useMemo(() => {
console.log("result calculating");
return count * 100;
}, [count]);
const handleClick = useCallback(() => console.log("CallbackMemoDemo click:", count), []);
return <div onClick={handleClick}>
{otherCount}--{count}--{result}
</div>
}
现在result的计算就和count变化同步了
小结: 1.useCallback一般用于存储函数,存储的函数函数体不发生更改(不会开辟新内存)
2.useMemo一般用于根据依赖(第二个参数)重新计算(计算可能比较耗时,而且计算只和这个或这几个依赖有关),依赖变化定义的函数体才会计算