它和useCallback一樣,也是返回有記憶的值。

import React, { memo, useState } from "react";
function calcNumTotal(num) {
console.log("calcNumTotal被執(zhí)行");
let total = 0;
for (let i = 1; i < num; i++) {
total += i;
}
return total;
}
const App = memo(() => {
const [count, setCount] = useState(0);
return (
<div>
<h2>計(jì)算結(jié)果:{calcNumTotal(50)}</h2>
<h2>count:{count}</h2>
<button onClick={(e) => setCount(count + 1)}>點(diǎn)我加1</button>
</div>
);
});
export default App;
每一次點(diǎn)擊button, <h2>計(jì)算結(jié)果:{calcNumTotal(50)}</h2>就會被重新渲染,calcNumTotal函數(shù)會被執(zhí)行。50并沒有改變,所以沒必要反復(fù)地被進(jìn)行調(diào)用
這樣給定義一個total變量的化,不會被反復(fù)執(zhí)行
import React, { memo, useState } from "react";
function calcNumTotal(num) {
console.log("calcNumTotal被執(zhí)行");
let total = 0;
for (let i = 1; i < num; i++) {
total += i;
}
return total;
}
let total = calcNumTotal(50);
const App = memo(() => {
const [count, setCount] = useState(0);
return (
<div>
<h2>計(jì)算結(jié)果:{total}</h2>
<h2>count:{count}</h2>
<button onClick={(e) => setCount(count + 1)}>點(diǎn)我加1</button>
</div>
);
});
export default App;
但是把total定義在組件外面,再去使用,不合適,而且total直接寫死了。
把total定義在App里面,也是會被反復(fù)的調(diào)用。
import React, { memo, useState } from "react";
function calcNumTotal(num) {
console.log("calcNumTotal被執(zhí)行");
let total = 0;
for (let i = 1; i < num; i++) {
total += i;
}
return total;
}
const App = memo(() => {
const [count, setCount] = useState(0);
let total = calcNumTotal(50);
return (
<div>
<h2>計(jì)算結(jié)果:{total}</h2>
<h2>count:{count}</h2>
<button onClick={(e) => setCount(count + 1)}>點(diǎn)我加1</button>
</div>
);
});
export default App;
這個時候就可以使用useMemo。useMomo傳入一個函數(shù),他優(yōu)化的是這個函數(shù)的返回值。
let result = useMemo(() => {
return calcNumTotal(50);
}, []);
用useMemo對返回結(jié)果做一個優(yōu)化。
第二個傳入空數(shù)組代表對什么都不依賴。
如果依賴count,[count]代表count改變,我里面的函數(shù)再重新執(zhí)行。
寫空數(shù)組代表我useMomo里面的函數(shù)和誰都沒有關(guān)系,這個函數(shù)不會被重新調(diào)用。返回的result永遠(yuǎn)是同一個值。
useMemo 和 useCallback的對比
function fn() {
console.log("increment");
setCount(count + 1);
}
const increment = useCallback(fn, []);
const increment2 = useMemo(() => fn, []);
/* 這兩個寫法相同。對什么都沒有依賴的時候,返回的值incrment都相同。一個是直接對函數(shù)做優(yōu)化,一個是對函數(shù)的返回結(jié)果做優(yōu)化 */
當(dāng)count發(fā)生改變的時候,useMemo里面的函數(shù)重新執(zhí)行,返回不同的結(jié)果。count改變的時候,里面的函數(shù)才會做一個執(zhí)行。
let result = useMemo(() => {
return calcNumTotal(count * 2);
}, [count]);
總結(jié)1:
1.如果函數(shù)里面有大量的計(jì)算,每次render的時候使用結(jié)果,useMemo對這個函數(shù)要不要重新執(zhí)行進(jìn)行優(yōu)化。用useMemo包裹的化,不對任何進(jìn)行依賴,是不會反復(fù)執(zhí)行這個函數(shù)的,一直使用同一個值。
如果把這兩個傳遞給子組件,會不會有區(qū)別

<HelloWorld result={result}></HelloWorld>
其實(shí)沒有區(qū)別,因?yàn)樽咏M件傳遞的都是一個數(shù)字。
如果是calcNumTotal(50) 那么子組件只有渲染一次,因?yàn)檫@個結(jié)果是一定的,而且子組件用了memo包裹。這個時候無論是有沒有用useMomo包裹這個函數(shù),子組件都是不會被渲染的。
但是如果是calcNumTotal(count * 2),子組件是每次都會被渲染的。
以上都是沒有區(qū)別的。
以下情況會有區(qū)別
import React, { memo, useMemo, useState } from "react";
const HelloWorld = memo(function (props) {
console.log("hellow");
return <h2>HelloWorld</h2>;
});
const App = memo(() => {
const [count, setCount] = useState(0);
const info = { name: "why", age: 18 };
return (
<div>
<h2>count:{count}</h2>
<button onClick={(e) => setCount(count + 1)}>點(diǎn)我加1</button>
<HelloWorld infp={info}></HelloWorld>
</div>
);
});
export default App;
當(dāng)count發(fā)生改變的時候,子組件會重新渲染。當(dāng)app函數(shù)重新執(zhí)行,const info ={}會重新定義一個新的對象,如果不希望重新給子組件渲染,就使用useMemo包裹
import React, { memo, useMemo, useState } from "react";
const HelloWorld = memo(function (props) {
console.log("hellow");
return <h2>HelloWorld</h2>;
});
const App = memo(() => {
const [count, setCount] = useState(0);
const info = useMemo(() => ({ name: "why", age: 18 }), []);
return (
<div>
<h2>count:{count}</h2>
<button onClick={(e) => setCount(count + 1)}>點(diǎn)我加1</button>
<HelloWorld infp={info}></HelloWorld>
</div>
);
});
export default App;
總結(jié)2
對子組件傳遞相同內(nèi)容的對象時候,使用useMemo可以進(jìn)行性能優(yōu)化。不讓子組件進(jìn)行多次渲染!(傳入值是沒有去別的,用memo包裹的話,子組件是不會重新渲染的)
優(yōu)化的點(diǎn)是2個!?。?!
useCallback就是只有1個,給子組件傳遞一個函數(shù)的時候進(jìn)行性能優(yōu)化?。〔蛔屪咏M件進(jìn)行多次渲染!