Reputation: 792
I've come up with the following code using React Transition Group:
const Transition = ({ elements, selectKey, render: Element, ...props }) => (
<TransitionGroup {...props}>
{elements.map((element) => (
<CSSTransition
key={selectKey(element)}
timeout={1000}
className="transition-slide"
>
<Element {...element} />
</CSSTransition>
))}
</TransitionGroup>
)
The key part here is that Transition
component receives the render
prop and renders it applying some transitions.
The way I expected for this to work:
<Transition render={(props) => <Toast {...props} />} />
But this code does not work as I expected: the transition of the next element interrupts the transition of the previous one.
However, this code works just fine:
const Element = (props) => <Toast {...props} />
// ...
<Transition render={Element} />
How can I fix this issue without putting the desired render-prop into a separate component?
Codesandbox: Example sandbox. The sandbox presents a non-working option with animation interruption. To get a working version, you need to uncomment lines 16 and 30 in the /Toasts/index.js
file
P.S. I can't just use
render={Toast}
because I need to do({id}) => <Toast dismiss={() => {deleteToast(id)}} />
. I omitted this detail in order to simplify the understanding of the problem.
Upvotes: 1
Views: 161
Reputation: 86
If you don't want to put the render function into another component, putting it into a useCallback() solved it for me.
const Toasts = () => {
const [toasts, addToast] = useToasts();
const Element = useCallback((props) => <Toast {...props} />, []);
return (
<div>
<button onClick={addToast}>Add toast</button>
<List>
<Transition
elements={toasts}
selectKey={({ id }) => id}
render={Element}
/>
</List>
</div>
);
}
(I don't quite understand the origin of the issue, but it has to do something with the function references.)
Upvotes: 1