Your approach rn is totally fine and common for apps with lightweight components or when you want to keep state in each subcomponent alive between views. I use it in most of my smaller React apps. But it's not always ideal, mostly performance wise.
Like in @moonstar-x's example, AnimatePresence
is sort of the best of both worlds. Here's a little example of my own:
import { AnimatePresence, motion } from 'framer-motion'
import { ComponentA } from './path/to/ComponentA'
<AnimatePresence mode="wait">
{currentComponent === 'A' && (
<motion.div
key="A"
initial={{ x: 300, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: -300, opacity: 0 }}
transition={{ duration: 0.3 }}
>
<ComponentA />
</motion.div>
)}
</AnimatePresence>