一句话来解释,useMemo是缓存值的,useCallback是缓存函数的。
一、useMemo:
接收两个参数,第一个参数是个函数,第二个是依赖项。返回一个memoized值,只有当它的某个依赖项改变时才重新计算 memoized 值,初始化的时候也会调用一次,这种优化有助于避免在每次渲染时都进行高开销的计算。
import React, {
useState, useMemo } from 'react';
export default function hook() {
const [count, setCount] = useState(1)
const [total, setTotal] = useState(1)
const memoizedValue = useMemo(() => {
console.log("只有total变了我才会变")
// 返回的值是total+1
return total + 1
}, [total]);
return (
<div>
<button onClick={
() => setCount(count + 1)}>count + 1</button>
<button onClick={
() => setTotal(total + 1)}>total + 1</button>
<div>count is {
count}</div>
<div>total is {
total}</div>
<div>memoizedValue is {
memoizedValue}</div>
</div>
)
}
二、useCallback
接收两个参数,第一个参数是个函数,第二个是依赖项。返回一个memoized函数,依赖项不变的情况下,memoizedCallback的引用不变。即:useCallback会被缓存,从而达到渲染性能优化的目的。
父组件:
export default function LearnUseCallBack() {
const [num, setNum] = useState(1);
const [count, setCount] = useState(1);
const add = useCallback(() => {
console.log("你好");
setNum(num + 1);
}, [count]);
return (
<div>
<div>缓存函数</div>
<button onClick={
add}>num + 1</button>
<button onClick={
() => setCount(count + 1)}>count + 1</button>
num ==> {
num}
count ==> {
count}
<ChildComponent add={
add}></ChildComponent>
</div>
);
}
子组件:
import React, {
useState, useCallback } from "react";
// react.memo会做一层浅比较
/**
* 因为我们每次触发render 都会重新执行一遍当前函数
* 所以说,我们的方法会重新赋值,react.memo时进行浅比较
* 重新赋值的方法和之前的方法,引用不一样,所以react.memo
* 会认为是一个新的对象,所以会重新渲染
*/
const ChildComponent = React.memo((props) => {
console.log("每次render都会触发吗?", props);
return (
<div>
<div>你好我是子组件</div>
</div>
);
});
注:若add方法不被缓存,因为add是引用类型,则组件刷新时add函数每次渲染时都指向不同的引用类型,若将add传给子组件,即使子组件使用了memo包裹,子组件还是每次都会刷新的,影响性能!我们只希望与子组件相关的值变化了之后子组件才去重新渲染。