I'd like to build a re-usable animation component with react-spring. Here's what I have so far:
const Fade = ({
show,
as = "div",
children
}: {
show: boolean;
as?: keyof JSX.IntrinsicElements;
children: React.ReactNode;
}) => {
const transitions = useTransition(show, null, {
from: { position: "absolute", opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
unique: true
});
const AnimatedComponent = animated[as];
return (
<>
{transitions.map(({ item, key, props }) => {
if (!item) {
return null;
}
return (
<AnimatedComponent key={key} style={props}>
{children}
</AnimatedComponent>
);
})}
</>
);
};
However, there's now an issue where the animation components introduces a "side-effect", adding a "div" wrapper around the child I want animated. This causes styling issues in existing components that would require lots of changes.
So as a workaround, I attempted to use animated
as a function, and pass children as a non-instantiated react element. But then there's noticeable jank and animation doesn't complete and stops mid-way through at times, e.g., inspect the animated element, and notice that the opacity tends to stop at 0.98883393 rather than at 1.
const Fade = ({
show,
children
}: {
show: boolean;
children: React.ReactElement;
}) => {
const transitions = useTransition(show, null, {
from: { position: "absolute", opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
unique: true
});
// Here's the change. We wrap children in a functional component and clone
// children inside
const AnimatedComponent = animated(({ style }) =>
React.cloneElement(children, { style })
);
return (
<>
{transitions.map(({ item, key, props }) => {
if (!item) {
return null;
}
return (
<AnimatedComponent key={key} style={props}>
{children}
</AnimatedComponent>
);
})}
</>
);
};
I've noticed that introducing extra "div" wrappers seems to be a side-effect with some of these animation-based libraries like react-spring and framer-motion
Is there a suggested way to build re-usable animation components with react-spring that doesn't come with the side-effect of introducing extra DOM elements