react中memo/useMemo/useCallback的使用

memo

使用memo包裹函数子组件,保证子组件只在props变化时重新渲染.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React, { useState,memo } from 'react';
import { render } from 'react-dom';


//如果Child组件不用memo包裹的话,即使App组件里面的age更新,与Child没有关系,Child还是会重新渲染
//使用memo包裹以后,App中 age的更新并不会引起Child的重新渲染

const Child = memo((props) => {
console.log('child render')
return <div>

{props.count}
</div>;
});
const App = () => {
console.log('app render')
const [count,setCount] = useState(0)
const [age,setAge] = useState(0)
return (
<div>
<Child count={count}/>
<p>age: {age}</p>
<button onClick={()=>{setAge(age+1)}}>add</button>

</div>
);
};

render(<App />, document.querySelector('#app'));

useCallback

把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。

1
2
3
4
5
6
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);

将函数指向同一引用,避免函数子组件因为props中函数引用变化而重新渲染.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, { useState, memo,useCallback } from 'react';
import { render } from 'react-dom';
const Child = memo(({ count,d }) => {
console.log('child render');
return <div>count:{count}</div>;
});
const App = () => {
console.log('app render');
const [count, setCount] = useState(0);
const [age, setAge] = useState(0);

//不用userCallback包裹传递给Child组件的函数时,每次更新age,App会重新渲染,
//changeCount这个函数会被重新创建,所以传给子组件的props发生了变化,因此Child
//会重新渲染.归根结底还是因为传递给props的是函数的引用,即时是同一个函数,引用也是不相同的
//使用useCallback包裹的话,react会将changeCount这个函数缓存,这样当age变化导致App重新渲染时,changeCount这个函数的引用并没有发生变化,所以也不会导致Child的重新渲染.

const changeCount = useCallback(() => {
setCount(count + 1);
},[]);

return (
<div>
<Child count={count} changeCount={changeCount} />
<p>age: {age}</p>
<button
onClick={() => {
setAge(age + 1);
}}
>
add
</button>
</div>
);
};
render(<App />, document.querySelector('#app'));

useMemo

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

1
useCallback(fn, deps)` 相当于 `useMemo(() => fn, deps)
1
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, { useState, memo, useCallback, useMemo } from 'react';
import { render } from 'react-dom';
const Child = memo(({ count, d }) => {
console.log('child render');
return <div>count:</div>;
});
const App = () => {
console.log('app render');
// const [count, setCount] = useState(0);
const [age, setAge] = useState(0);



const count = useMemo(()=>{
return {
name: 1,
age: 2,
}
},[]);

return (
<div>
<Child count={count} />
<p>age: {age}</p>
<button
onClick={() => {
setAge(age + 1);
}}
>
add
</button>
</div>
);
};
render(<App />, document.querySelector('#app'));
thank u !