Is it safe to do this:
function Parent() {
const myRef = useRef([1, 2, 3]);
console.log("parent: " + myRef.current);
return <Child myList={myRef.current} />;
}
function Child({ myList }) {
const [currInt, setCurrInt] = useState(4);
console.log("child: " + myList);
return (
<Button
onClick={() => {
myList.push(currInt);
setCurrInt((n) => n + 1);
}}
/>
);
}
Output:
parent: 1,2,3
child: 1,2,3
<click>
child: 1,2,3,4
<click>
child: 1,2,3,4,5
...
I know the parent won’t rerender upon updates of myList and that is the expected behavior.
I just wonder if this goes against any kind of React principles or could break in the future.
Previously I had stored the initial list passed down from Parent in another ref inside the Child component and this worked as well. However, it does not seem to be necessary if I can just mutated the parent ref object.
2
Answers
Why it’s feasible
Actually, if you consider this situation purely from a JavaScript perspective, there’s no issue because the Child and Parent components share the same object. This object’s memory address remains unchanged upon the Parent’s re-render, thanks to the use of useRef.
Why not
However, adopting this approach may lead to confusion regarding the data flow. In React, I recommend employing pure functions to ensure a clear and predictable data stream. It’s advisable to avoid ambiguous data transfers as much as possible. I believe that the key to efficient development lies in making the codebase easily maintainable and update-friendly.
Summary
Although this violates some of React’s core principles, such as data flowing down from parent to child, this capability is necessary in certain scenarios. Therefore, it exists as an escape hatch.
To get this done you need to wrap the
Child
insideforwardRef
& pass the take ref object as a prop.& for advance functionality you can use
useImperativeHandle
hooks.https://react.dev/reference/react/forwardRef
https://react.dev/reference/react/useImperativeHandle