We have seen that we can cache something that is "expensive", using useMemo(), in https://dev.to/kennethlum/seeing-usememo-speed-up-our-webpage-3h91
Now a function can be quite simple, but why would we want to cache it to? It can be when we pass into a child component or use it else where, and we want to keep it the same value, so that there is no unnecessary re-rendering.
We can see, in
export default function App() {
const myFooter = useMemo(() => <Footer n={30000} />, []);
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
The function handleClick is a new function every time App() is called.
We can use useMemo() to cache it too, just like how we cache <Footer />
The code:
Wrong behavior demo: https://codesandbox.io/s/relaxed-newton-5sqmy?file=/src/App.js
const handleClick = useMemo(
() => () => {
setCount(count + 1);
},
[]
);
It can only increment the count to 1, but not more. Why is that? The reason is that we cached the function, which is a closure with the scope chain with count equal to 0. Every time, the function sees count as 0, and therefore the setCount(count + 1) is always setCount(0 + 1).
To fix that behavior, we can use:
const handleClick = useMemo(
() => () => {
setCount(c => c + 1);
},
[]
);
Demo: https://codesandbox.io/s/nameless-fast-d0fv1?file=/src/App.js
Note that we don't need to use useMemo(), but can use useCallback(). It is essentially the same thing:
const handleClick = useCallback(() => {
setCount((c) => c + 1);
}, []);
Demo: https://codesandbox.io/s/busy-archimedes-vse8f?file=/src/App.js
Note that we don't need to give a function that return a value, but can provide that function we want to cache directly.
Likewise, if we have
const handleClick = useCallback(() => {
setCount(count + 1);
}, []);
It is not going to work: https://codesandbox.io/s/distracted-cloud-o93gw?file=/src/App.js
To see that handleClick is the same value (a reference to the same function), we can use a useRef() to double check it. We can skip this part if useRef() is not familiar to you yet:
const checkingIt = useRef(null);
const handleClick = useCallback(() => {
setCount((c) => c + 1);
}, []);
console.log(checkingIt.current === handleClick);
checkingIt.current = handleClick;
Demo: https://codesandbox.io/s/unruffled-sunset-81vwx?file=/src/App.js
We can see that the first time, the console.log() would print out false, but once we set it, the next time App() is called, it has the same value as the previous time, and would print out true.
If we change it to a new function every time, then it would print out false every time.
Demo: https://codesandbox.io/s/affectionate-dewdney-556mn?file=/src/App.js
Top comments (0)