Your React.memo is Lying to You. Here’s Why useCallback is the Answer.
You have a component that’s re-rendering way too often. You identify an expensive child component, wrap it in React.memo .But then you open the profiler, and it’s still re-rendering every single time the parent does.
It’s not broken, but it’s being tripped up by one of JavaScript’s fundamental truths: functions are objects. And in the world of React, that little detail can cost you dearly in performance.
Today, we’ll unravel this mystery and show how the useCallback hook is the key to making your optimizations actually work.
When React.memo Fails
We have a ParentComponent that holds some state, and it passes a function down to a ChildComponent. To prevent the child from re-rendering unnecessarily, we've wrapped it in React.memo.
As a quick refresher, React.memo is a higher-order component that tells React, "Don't re-render this component unless its props change." It does this by doing a shallow comparison of the old props and the new props.
Here’s our code:
import React, { useState } from 'react';
// An "expensive" child component we want to protect from re-renders
const ChildComponent = React.memo(
({ onButtonClick }: { onButtonClick: () => void }) => {
console.log("ChildComponent is re-rendering! Why?");
return <button onClick={onButtonClick}>Click Me</button>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
// This function is passed as a prop to the child
const handleButtonClick = () => {
console.log("Button was clicked!");
};
return (
<div>
{/* This button's only job is to cause the Parent to re-render */}
<button onClick={() => setCount(count + 1)}>
Re-render Parent: {count}
</button>
<ChildComponent onButtonClick={handleButtonClick} />
</div>
);
};When you run this and click the “Re-render Parent” button, you’ll see ChildComponent is re-rendering! Why? in the console every single time.
But why? The child’s props haven’t really changed, have they?
The problem lies in how JavaScript handles equality. Every time ParentComponent re-renders, the handleButtonClick function is re-created from scratch.
It might do the same thing, but it’s a brand new function in memory. For React.memo's shallow comparison, oldProps.onButtonClick === newProps.onButtonClick is always false. The old function and the new function are two different objects (Different addresses in memory).
useCallback to the Rescue
This is the exact problem useCallback was designed to solve. It lets us memoize a function, giving it a stable identity across renders.
Let’s fix our ParentComponent:
import React, { useState, useCallback } from 'react';
// ChildComponent remains the same
const ChildComponent = React.memo(/* ... */);
const ParentComponent = () => {
const [count, setCount] = useState(0);
// This function is now MEMOIZED
const handleButtonClick = useCallback(() => {
console.log("Button was clicked!");
}, []); // The dependency array
return (
<div>
<button onClick={() => setCount(count + 1)}>
Re-render Parent: {count}
</button>
<ChildComponent onButtonClick={handleButtonClick} />
</div>
);
};By wrapping our function definition in useCallback and providing an empty dependency array [], we're telling React to create this function once, on the very first render, and then give back that exact same function instance every other time.
Share your codes
ReplyDeletepc4software giving rapitgator link
ReplyDelete
ReplyDeleteBlog Redirect
https://docs.google.com/document/d/1x-f20PUt4fkyzIoBL2Ci0Ef2MpUA4MidlFV53n8A0NM/edit?usp=sharing