Reputation: 19329
In the code below, how can I update only Component B and not Component A (or the Parent Component)
Component A:
const A = ({ data, clickCallback }) => {
console.debug('A');
return (<button onClick={clickCallback}>Component A</button>)
};
Component B:
const B = ({ filteredData }) => {
console.debug('B');
return <h1>Component B: {filteredData}</h1>;
};
Parent Component:
function Parent() {
console.debug('parent');
const [data, setData] = useState(0);
const handleClick = () => {
setData(data + 1);
};
return (
<div>
<A clickCallback={handleClick}/>
<B filteredData={data} />
</div>
);
}
So when clicking on the Component A button, I only see console.debug('B') in the console?
parent
A
B
B
B
...
Here is the link to the working code: https://codesandbox.io/s/musing-lehmann-kme8d?file=/src/index.js:233-245
NOTE: I have tried wrapping the handleClick inside a useCallback()
but, still in the console I see:
parent
A
B
parent
A
B
...
Upvotes: 0
Views: 535
Reputation: 202751
With functional components, they are rerendered when their parent component rerenders. I.E. When Parent
rerenders, then both A and
B` will be rerendered in the "render phase" in order to compute a diff. This should not be confused with rendering to the DOM during the "commit phase".
You can wrap A
in the memo
Higher Order Component and pass a custom equality function that returns true/false if the previous and next props are equal.
By default it will only shallowly compare complex objects in the props object. If you want control over the comparison, you can also provide a custom comparison function as the second argument.
function MyComponent(props) { /* render using props */ } function areEqual(prevProps, nextProps) { /* return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false */ } export default React.memo(MyComponent, areEqual);
I suggest also correctly console logging in an useEffect
so you truly know when the component is rerendered to the DOM.
A functional state update should also be used to update the data
state so the state value isn't closed over in the callback scope.
const A = ({ data, clickCallback }) => {
useEffect(() => {
console.debug("A");
});
return <button onClick={clickCallback}>Component A</button>;
};
const MemoA = memo(
A,
(prevProps, nextProps) => prevProps.data === nextProps.data
);
const B = ({ filteredData }) => {
useEffect(() => {
console.debug("B");
});
return <h1>Component B: {filteredData}</h1>;
};
function Parent() {
useEffect(() => {
console.debug("parent");
});
const [data, setData] = useState(0);
const handleClick = () => {
setData(data => data + 1); // <-- functional update
};
return (
<div>
<MemoA clickCallback={handleClick} />
<B filteredData={data} />
</div>
);
}
Upvotes: 1