Reputation: 1572
I have this case:
const Parent = () => {
const [value, setValue] = useState('');
return <>
<Child1 value={value} />
<Child2 setValue={setValue} />
</>
}
but every time setValue
of Child2
is getting called, Child2
re-renders although its props have not been changed (Child1 re-renders also, but this is the expected behavior since prop value
changed).
How to fix this ?
Upvotes: 3
Views: 9231
Reputation: 202836
React useState
state updater functions are guaranteed to be stable references, so Child2
is only rerendering because the parent component Parent
is rerendering due to the state update. If you want to hint to React that it can likely bail on rerendering a child component then use the memo Higher Order Component.
const Child2 = ({ setValue }) => {
....
};
export default memo(Child2);
Demonstrates 2 "instances" of Child 2, one decorated with the memo
HOC and the other not. All children use an useEffect
to log when they are rendered. Note that all initially render, but only child 1 and 2 (w/o memo) continually are rerendered.
Sandbox code:
import { memo, useEffect, useState } from "react";
import "./styles.css";
const Child1 = ({ value }) => {
useEffect(() => console.log("Child 1 rendered"));
return <div>Child1: {value}</div>;
};
const Child2 = ({ id, setValue }) => {
useEffect(() => console.log(`${id} rendered`));
return (
<div>
{id}: <input type="text" onChange={(e) => setValue(e.target.value)} />
</div>
);
};
const Child2wMemo = memo(Child2);
const Parent = () => {
const [value, setValue] = useState("");
return (
<>
<Child1 value={value} />
<Child2 id="Child 2" setValue={setValue} />
<Child2wMemo id="Child 2 with Memo" setValue={setValue} />
</>
);
};
export default function App() {
return (
<div className="App">
<Parent />
</div>
);
}
Upvotes: 2
Reputation: 14619
This is the purpose of React.memo or useMemo.
Example
const Parent = () => {
const [value, setValue] = useState('');
const child2 = useMemo(() => <Child2 setValue={setValue} />, [setValue])
return <>
<Child1 value={value} />
{child2}
</>
}
[setValue]
Is the dependencies array. Changes to anything in this array will cause the value to be re-calculated.
The reason it re-renders even though the props don't change is because you are changing state on the Parent component. This causes the Parent component to re-render, which will re-render all of the children regardless of whether their props change.
Alternatively, you could use React.memo on the child component like this:
const Child2 = React.memo(function Child2(props) {
/* ... */
});
Upvotes: 2