You basically have a global part of the component and a local part. The global part is what actually gets rendered when necessary and manages current state, the local part defines what content will be rendered inside the global part for a particular trigger and interacts with the global part when a trigger condition happens (eg hover timeout for a tooltip).
This is, in general, the idea that is being solved by native interaction with the DOM. It stores the graphic, so it doesn't have to be re-instated every time. Gets hidden with "display:none" or something. When it needs to display something, just the content gets swapped and the object gets 'unhidden'.
Good luck.
Excessive nodes - hidden or not - cost memory. On midrange Android it’s scarce and even if you’re not pushing against overall device memory limit, the system is more likely to kill your tab in the background if you’ve got a lot going on.
The tradeoff is for more complicated components, first renders can be slower.
https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-s...
And the “react way” is to have the UI reflect state. If the state says the modal is not being rendered, it should not be rendered
There are many high quality third party tools to help with this, such as Motion’s <AnimatePresence> (https://motion.dev/docs/react-animate-presence). I haven’t used the library you mentioned, but it seems somewhat unmaintained and isn’t compatible with react-dom@19.
First party support is coming to React with the new <ViewTransition> component (https://react.dev/reference/react/ViewTransition).
If you insist that only the React maintainers are allowed to diverge DOM state from the render tree or write code you don’t understand, you can adopt it today from react{,-dom}@experimental. It’s been available there since April (https://react.dev/blog/2025/04/23/react-labs-view-transition...).
https://stackblitz.com/edit/react-modal-with-transition-out?...
Ok it all makes sense now. I’d forgotten about useLayoutEffect. Haven’t had to write much react recently.
Similarly, adding a modal like this
{isOpen && <Modal isOpen={isOpen} onClose={onClose} />}
instead of
<Modal isOpen={isOpen} onClose={onClose} />
Seems to make the app smoother the more models we had. Rendering the UI (not downloading the code, this is still part of the bundle) only when you need it seems to be a low hanging fruit for optimizing performance.