在 React.memo的文章有提到,每次component更新(re-evaluate)都會產生長得一模一樣的新函式物件,所以當新的函式物件當作props傳入child component,child component會因為傳入的函式物件不同而跟著parent component更新。
那要如何讓component更新時不會產生新的函式物件?
答案就是用 useCallback
。
useCallback
useCallback
是React用來儲存函式物件的hook,並能保證每次component更新時使用的都是和前一次更新相同的函式,也就是同一個位址的函是物件。
// App.js (parent component)
import {useState, useCallback} from 'react';
import Me from './Me';
import Button from './Button';
export default function App(){
console.log('App loads');
const [isMe, setIsMe] = useState(false);
// Use useCallback hook
const addMe = useCallback((event) => {
event.preventDefault();
setIsMe((prevMe) => !prevMe);
}, []);
return (
<>
<h1>h1 always here</h1>
<Me me={false}/>
<Button onClick={addMe}>Click and Add Me!</Button>
</>
)
}
useCallback
讓component更新時不會創造一個長得一模一樣卻是儲存在不同地方的新函式,也因此每次傳入Button component的addMe函式props就會是相同的。
此外,這篇文章 在討論如何正確地用 removeEventListener
移除事件監聽器,而這個問題的原因就是每次Component更新會產生看起來名稱相同、但其實是不同物件的函式,因此沒辦法正常使用 removeEventListener
。其中一個解決辦法就是用 useCallback
hook;而文章下面留言有提到另一個辦法是使用useEffect
來處理這個問題,而且會處理的會更好。
References
- useCallback @React Docs
- React Hooks Tutorial - 26 - useCallback Hook
- React - The Complete Guide (incl Hooks, React Router, Redux)
- How to (really) remove eventListeners in React
- 如何錯誤地使用 React hooks useCallback 來保存相同的 function instance
- Memoization @Wikipedia