雖然說之前已經認識了 useCallback、useMemo,但有時還是對於什麼時候要用它們的時機有些模糊,所以就透過這篇文章釐清觀念。
首先要知道一點是如果沒有必要可以不用去用它們。盲目的使用反而更耗效能,因為它們在 React 底層記憶值也是需要消耗效能的,同時程式碼也會變得更複雜。
在此先複習一下 Referential Equality,對於理解後面的內容會有所幫助。
我們知道陣列、物件、函式等物件型別擁有 call by reference 的特性,所以即使有兩個物件它們裡面的元素、屬性、函式內容都一樣,在做 ===
比較時仍然會是 false。
const hero1 = {
name: 'Batman'
};
const hero2 = {
name: 'Batman'
};
console.log(hero1 === hero1); // => true
console.log(hero1 === hero2); // => false
這樣跟 React 又有什麼關係?讓我們繼續看下去!
在下面的範例可以看到一個被 React.memo() 包覆的元件 Child,而且接收到一個函式 onClick 當作 props。
父元件重新渲染時,雖然都還是同一個函式,但函式被重新產生了,所以 React.memo() 會以為傳入的 props 改變而重新渲染 Child 元件,所以加上了 useCallback。
function Parent() {
const [count, setCount] = useState(0);
const onClick = useCallback(() => {
console.log('click');
}, []);
return (
<>
<Foo onClick={onClick} />
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>count increment</button>
</>
);
}
const Child = memo({ onClick }) => {
// ...略
return (
<>
// ...
<button onClick={onClick}>可點擊</button>
</>
)
});
useEffect 的 dependency array 的其中一個元素為物件型別時,若物件重新產生就會被 useEffect 當作 dependency array 改變,像以下的例子就造成了 useEffect 無限 render,所以也需要加上 useCallback。
跟此範例類似的例子在 pjchender 大大的 從 Hooks 開始,讓你的網頁 React 起來 Day20 篇 也有提到,有興趣的讀者可以跳到"在 useEffect 的 dependencies 中放入函式 - useCallback 的使用"的段落去閱讀。
const App = () => {
const [id, setId] = useState(1);
const [detail, setDetail] = useState("");
const getDetail = useCallback(() => {
fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then(res => res.json())
.then(json => {
setDetail(json); // state updated
}));
}, [id]);
useEffect(() => {
getDetail();
}, [getDetail]);
return (
<>
<p>{detail.name}</p>
<p>Current id: {id}</p>
<button onClick={() => setId(id + 1)}>id increment</button>
</>
);
}
Referential Equality 的概念也可以套用在 useMemo,所以也可以留意一下 useEffect 的 dependency array。
const App = ({ param1, param2 }) => {
const params = useMemo(() => {
return { param1, param2, param3: 1 };
}, [param1, param2]);
useEffect(() => {
callApi(params);
}, [params]);
}
例如 filter 很多元素的陣列、複雜數學運算
How To Use Memoization To Drastically Increase React Performance
When to useMemo and useCallback
如何錯誤地使用 React hooks useCallback 來保存相同的 function instance
蠻好奇使用 useMemo 或是 useCallback Hooks 後
整個page是否能真的提升多少效能
不錯的問題!之前看 useMemo 或是 useCallback 的教學大多也是教你怎麼使用 or 何時用,到是還沒真的看過使用前後的效能比較