Recently I saw code akin to the following contrived example:
const MyComp = props => {
const [prevProps, setPrevProps] = useState(props)
if (props !== prevProps) {
setPrevProps(props);
// do something else...
}
}
The ponent uses some kind of derived state to remember the previous props. If the memory location of props
has changed (props !== prevProps
), it will sync the new props to useState
.
Yeah, it doesn't make that much sense, but my point is: Does React make any guarantees, that the object reference of props
stays the same, given no contained property of props
has changed?
At least, this seems to be the case for the tests I have done. If a parent ponent changes any of the props, there will be a new props
object created.
I would appreciate any official documentation link proving this.
Recently I saw code akin to the following contrived example:
const MyComp = props => {
const [prevProps, setPrevProps] = useState(props)
if (props !== prevProps) {
setPrevProps(props);
// do something else...
}
}
The ponent uses some kind of derived state to remember the previous props. If the memory location of props
has changed (props !== prevProps
), it will sync the new props to useState
.
Yeah, it doesn't make that much sense, but my point is: Does React make any guarantees, that the object reference of props
stays the same, given no contained property of props
has changed?
At least, this seems to be the case for the tests I have done. If a parent ponent changes any of the props, there will be a new props
object created.
I would appreciate any official documentation link proving this.
Share Improve this question asked Mar 12, 2020 at 13:10 bela53bela53 3,4851 gold badge15 silver badges29 bronze badges 01 Answer
Reset to default 9Does React make any guarantees, that the object reference of props stays the same, given no contained property of props has changed?
No, it doesn't.
If a parent ponent changes any of the props, there will be a new props object created.
If the parent re-renders, the child will always receive its props in a new object, even if nothing in it has changed.
If you want to prevent that, you will have to use
PureComponent
or React.memo
which will perform a shallow equal parison of all the properties of the props
object and prevent re-rendering if none of them changed.
const { memo, useState, useEffect } = React;
const Child = props => {
// only gets called when `props` changes
useEffect(() => console.log(props.name, ": props changed"), [props]);
return <p>{props.name}: {props.text}</p>;
};
const MemoChild = memo(Child);
const Parent = () => {
const [count, setCount] = useState(0);
const [text, setText] = useState("foo");
const handleTextChange = event => setText(event.target.value);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>
Click to force Re-Render
</button>
<input id="text" value={text} onChange={handleTextChange} />
<Child name="Child without memo()" text={text} />
<MemoChild name="Child with memo()" text={text} />
</div>
);
};
ReactDOM.render(<Parent />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Have a look at this example. You will see that when you press the button, the child not using memo
will re-render, even if the props name
or text
have not changed. It will still receive a new props
object.
But when you enter something into the input, both ponents re-render, because the text
property of the props changed.
It should also be noted that this is only a performance optimization. You should not rely on memo
preventing a re-render at all times.
This method only exists as a performance optimization. Do not rely on it to “prevent” a render, as this can lead to bugs.