This may be a somewhat advanced question:
React says: if there are two <Counter /> components but if any one is at the same DOM tree position, it is treated as the same component, and so there is no unmounting and the state will stay:
The React docs: https://react.dev/learn/preserving-and-resetting-state#same-component-at-the-same-position-preserves-state
The code:
export default function App() {
const [isFancy, setIsFancy] = useState(false);
return (
<div>
{isFancy ? (
<Counter isFancy={true} />
) : (
<Counter isFancy={false} />
)}
<label>
<input
...
(Note: not that we would write code like that. In real life we'd probably write only one line: <Counter isFancy={isFancy} />, but this is just to show the effect.)
I also put two demos on Codesandbox. Written in a similar way, and confirms with what the docs say:
https://codesandbox.io/p/sandbox/romantic-clarke-wtzdcc?file=%2Fsrc%2FApp.js
https://codesandbox.io/p/sandbox/rough-fast-d29rn7?file=%2Fsrc%2FApp.js
It appears as a strange rule, because they are really two instances, but if that is how React works, so be it.
However, if I try to write it in a slightly different way:
https://codesandbox.io/p/sandbox/musing-sea-mz3qq4?file=%2Fsrc%2FApp.js
return (
<div className="App">
{isFancy && <Counter isFancy={true} />}
{!isFancy && <Counter isFancy={false} />}
{theToggle}
</div>
);
Then all of a sudden, the counter will reset itself if I toggle "Fancy or not". (if I increase the count to 3, and toggle it. Now the count will reset to 0).
Why is that?
P.S. More thinking into it:
Really, every time App is re-rendered, Counter really is a brand new created instance, even if it is as simple as:
return <Counter isFancy={isFancy} />;
so React doesn't care if it is a new instance. It only cares if it is a component with this name at this position.
I might be totally wrong, but I think that there is a difference for react
In this example:
<div className="App">
{isFancy && <Counter isFancy={true} />}
{!isFancy && <Counter isFancy={false} />}
{theToggle}
</div>
React will see:
[false, Counter component, some jsx]
And here:
<div className="App">
{isFancy ? <Counter isFancy={true} /> : <Counter isFancy={false} />}
{theToggle}
</div>
[Counter component, some jsx]
I know that the docs clearly say that:
it’s the position in the UI tree — not in the JSX markup—that matters to React!
but maybe they meant something different with UI tree
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With