默認(rèn)情況下窗慎,React 每次重新渲染時都會重新運(yùn)行組件的整個主體训柴。
優(yōu)化重新渲染性能的常見方法是跳過不必要的工作缸濒。 例如,可以告訴 React 重用緩存的計(jì)算植榕,或者如果數(shù)據(jù)自上次渲染以來沒有更改再沧,則跳過重新渲染。
要跳過計(jì)算和不必要的重新渲染尊残,請使用以下 Hooks 之一:
-
useMemo
緩存計(jì)算結(jié)果炒瘸。 -
useCallback
緩存函數(shù)定義,再傳遞給優(yōu)化組件寝衫。
要優(yōu)先考慮渲染顷扩,請使用以下 Hooks 之一: -
useTransition
將狀態(tài)轉(zhuǎn)換標(biāo)記為非阻塞并允許其他更新中斷它。 -
useDeferredValue
可以推遲更新 UI 的非關(guān)鍵部分慰毅,并讓其他部分先更新隘截。
useMemo
useMemo 會在重新渲染之間緩存calculateValue結(jié)果,直到dependencies發(fā)生變化汹胃,第二個參數(shù)不傳的話婶芭,會每次都調(diào)用計(jì)算函數(shù)。
const cachedValue = useMemo(calculateValue, dependencies)
定義
參數(shù)
calculateValue
: 不帶任何參數(shù)着饥,例如 () =>犀农,并返回想要計(jì)算的值。dependencies如果改變宰掉,會重新調(diào)用該函數(shù)呵哨。dependencies
: 依賴項(xiàng)列表,包括組件中計(jì)算中使用的每個值轨奄。例如:[todos, tab](通過Object.is
比較dependencies兩次的值孟害。
返回值
在初始渲染中,“useMemo”返回不帶參數(shù)調(diào)用“calculateValue”的結(jié)果挪拟。
在下一次渲染期間挨务,它將返回上次渲染中已存儲的值(如果依賴項(xiàng)未更改),或者再次調(diào)用“calculateValue”舞丛,并返回“calculateValue”返回的結(jié)果耘子。
用法
1.跳過重新計(jì)算
1.當(dāng) List 的 props 與上次渲染時相同時果漾,可以通過將其包裝在 memo
:
中來告訴 List 跳過重新渲染:
import { useMemo, useState } from "react";
export function MemoDemo() {
const [name, setName] = useState("Tom");
const [todoList, setTodoList] = useState(["1", "2", "3"]);
const todoData: any = useMemo(() => {
return todoList.filter((item) => item != "1");
}, [todoList]);
return (
<div>
<div
onClick={() => {
setName("Lisa"); //click的時候球切, 不會在調(diào)用filter方法
}}
>
memo {name}
</div>
<List todoList={todoData}></List>
</div>
);
}
function List({ todoList }) {
return todoList.map((item) => <span key="item">{item}</span>);
}
2.記住另一個hook的依賴項(xiàng)
function Dropdown({ allItems, text }) {
const searchOptions = { matchMode: 'whole-word', text };
const visibleItems = useMemo(() => {
return searchItems(allItems, searchOptions);
}, [allItems, searchOptions]); // ?? 注意: dependency是在組件中創(chuàng)建的object
// ...
上述dependency是在組件中創(chuàng)建的object,每次組件在渲染的時候都會重新創(chuàng)建一個searchOption對象绒障,每次都是不同的searchOptions對象吨凑, 所以visibleItems每次渲染都會執(zhí)行。
如何解決這個問題?可以將searchOptions對象也通過useMemo存儲下鸵钝。
function Dropdown({ allItems, text }) {
const searchOptions = useMemo(() => {
return { matchMode: 'whole-word', text };
}, [text]); // ? Only changes when text changes
const visibleItems = useMemo(() => {
return searchItems(allItems, searchOptions);
}, [allItems, searchOptions]); // ? Only changes when allItems or searchOptions changes
// ...
進(jìn)一步的優(yōu)化糙臼,可以將searchOptions對象放在useMemo計(jì)算方法內(nèi)
function Dropdown({ allItems, text }) {
const visibleItems = useMemo(() => {
const searchOptions = { matchMode: 'whole-word', text };
return searchItems(allItems, searchOptions);
}, [allItems, text]); // ? Only changes when allItems or text changes
// ...
3.緩存一個方法
export default function ProductPage({ productId, referrer }) {
function handleSubmit(orderDetails) {
post('/product/' + productId + '/buy', {
referrer,
orderDetails
});
}
return <Form onSubmit={handleSubmit} />;
}
注意:{}, (){}, ()=> {},這種聲明在重新渲染時, 會創(chuàng)建一個新的函數(shù)恩商,那么對于緩存來說变逃,會認(rèn)為是不同的方法。
如何優(yōu)化怠堪?
export default function Page({ productId, referrer }) {
const handleSubmit = useMemo(() => {
return (orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails
});
};
}, [productId, referrer]);
return <Form onSubmit={handleSubmit} />;
}
這樣看著有些繁瑣揽乱,進(jìn)一步優(yōu)化,使用useCallback
export default function Page({ productId, referrer }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails
});
}, [productId, referrer]);
return <Form onSubmit={handleSubmit} />;
}
好了粟矿,那我們的useMemo到這里就結(jié)束了凰棉。
寶子們可以收藏評論交流哦