bug ?
I'm trying to mix CSStransition and dynamical imports. But I'm not able to make it work properly.
The animation classes are not applied on the second item:

I created a little demo available there: https://callmemagnus.github.io/bugs-async-csstransition/.
The code is there: https://github.com/callmemagnus/bugs-async-csstransition
If you click on the button: 2 components will be added one is a "normal" import (ending in the bundle) and the second is an async import (which is loaded async).
I load the module using this technique:
import React from 'react';
const asyncComponent = (importComponent) => {
return class extends React.Component {
state = {
component: null
}
componentDidMount() {
importComponent()
.then(({ default: component }) => this.setState({ component }))
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
}
}
export default asyncComponent;
Available here: https://github.com/callmemagnus/bugs-async-csstransition/blob/master/src/asyncComponent.js
I'm wondering if there is a way to make it work.
Anyone have an idea ?
I have the same problem
I now use Suspense and lazy from React 16.6 to do it.
I have the same problem
+1
+1
I now use Suspense and lazy from React 16.6 to do it.
Forgot to say. This is a good solution.
If it works correctly with Suspense, React's API recommended for lazily loading components, I don't consider this a bug. Let me know if I misunderstood the issue and I'll reopen. 馃槈
fixed! I wrap the async component with a component
Same bug here. It works correctly if lazy loading components are loaded once (i.e. no suspense component appears), but for the very first time CSS transition class names are applied to the Suspense component, but not the component that are loading lazily.
EDIT: I had to wrap Suspense component with a div, as CSSTransition applies the class names to its first child DOM element. If the first child is the Suspense component, suspense inject its fallback DOM element conditionally, so CSSTransition class names are removed by the Suspense DOM element. With the wrapping div the applied CSS class names are stable. In short:
<TransitionGroup>
<CSSTransition>
<div>
<Suspense fallback={...}>
<Switch>
...
I have written a blog post about how I have accomplished this here:
https://romiem.com/blog/animating-react-router
Worth noting that if you use the method from @kazinad (wrapping suspense with a div) that the animation may start before suspense has had a chance to load and render the lazy loaded module.
In my case, where I am lazy loading react-router routes, I found it better to apply a top level class to each of my routes (e.g. .a-routeFadeIn) and then define the style like this:
.a-routeFadeIn {
animation: a-routeFadeIn 0.75s ease-in 0.25s;
animation-fill-mode: both;
}
@keyframes a-routeFadeIn {
0% { opacity: 0; height: 0; overflow: hidden; }
0.01% { height: auto; overflow: visible; }
100% { opacity: 1; }
}
.a-routeFadeIn.fade-exit {
animation: none;
animation-fill-mode: none;
opacity: 1;
transition: opacity 0.2s ease-in;
}
.a-routeFadeIn.fade-exit-active {
opacity: 0;
}
The benefit of using animation is that it will always execute as soon as the component is mounted (unlike CSS transition styles which need to be applied after render).
Most helpful comment
Same bug here. It works correctly if lazy loading components are loaded once (i.e. no suspense component appears), but for the very first time CSS transition class names are applied to the Suspense component, but not the component that are loading lazily.
EDIT: I had to wrap Suspense component with a div, as CSSTransition applies the class names to its first child DOM element. If the first child is the Suspense component, suspense inject its fallback DOM element conditionally, so CSSTransition class names are removed by the Suspense DOM element. With the wrapping div the applied CSS class names are stable. In short: