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)