I have a dynamic array (state) of React components – and each components has an entry-animation on mount. But every time a component is added to the array all the components re-renders – which also triggers the entry-animation for all components...
My parent page looks something like this:
export default function Home({ projects }) {
const [components, setComponents] = useState([]);
const createComponent = (project) => {
const id = uniqid();
const temp = <Project block={project} key={id} />;
setOpenBlocks((prevState) => [temp, ...prevState]);
};
return (
<>
//Small images / Create component on click:
<div>
{projects.map((project, i) =>
<div key={project.page.id}>
<Image src alt
onClick={() => createComponent(project)}
/>
</div>
})}
</div>
//Big images / render array of components:
<div>
{components &&
components.map((block, i) => <Fragment key={i}>{component}</Fragment>)}
</div>
</>
);
}
And my 'Project' (child) component looks like this:
export default function Project({ project }) {
const [loaded, setLoaded] = useState(0);
return (
<AnimatePresence>
{project && (
<motion.figure
initial={{ width: 0 }}
animate={{ width: "100%" }}
style={{ opacity: loaded }}
>
<img
onLoad={() => setLoaded(1)}
/>
</motion.figure>
)}
</AnimatePresence>
)
}
So the entry-animation is made via the framer-motion AnimatePresence component, as well as the onLoad function changing opacity from 0 to 1. Both of them re-triggers when updating the array. And I need only the component that was just added to animate!
The child components props will not change once it is rendered.
I've tried wrapping the child component in 'memo', and tried updating the array with useCallback. Inserting the array like this somehow seemed to work (but I don't think it should?):
<div>
{components}
</div>
All input is welcome, thanks!