My coworker and I are trying to wrap redux-simple-router
navigation (which we've had working for a while) in a ReactTransitionGroup
element so that its lifecycle methods can be called on a route change. We've tried a whole bunch of versions, but haven't figured out a way to get it working.
Our current iteration creates a wrapper right under the ReactTransitionGroup
(which is a child of Provider
) so that lifecycle methods can be defined at a place where both the route state and children are accessible. This wrapper's render and componentWillAppear
methods are definitely called on initial app load (in the browser), but not when navigating (using Redux Simple Router) between pages in the app. That code, more or less, is on this gist.
Most notably, we tried the cloneElement
method from React with a regenerated key (e.g., through history.createKey()
) each time, but couldn't get the lifecycle methods to fire on any route changes.
What's the idiomatic way to wrap simple-router components in a ReactTransitionGroup
with redux-simple-router
?
UPDATES
I've tried a new version, in which I wrap each individual route with its own TransitionWrapper
class, as in this second gist (inspired by this answer).
When that TransitionWrapper
extends React.Component
(as in the example), the render
method is called, but nothing else. The site works fine (but I can't access the transition hooks).
When it extends ReactTransitionGroup
, I hit an error on line 99 of the performAppear
method on the ReactTransitionGroup
object, a snippet of which is below:
performAppear: function (key) {
this.currentlyTransitioningKeys[key] = true;
var component = this.refs[key];
if (component.componentWillAppear) { /* error here */
component.componentWillAppear(this._handleDoneAppearing.bind(this, key));
} else {
this._handleDoneAppearing(key);
}
Uncaught TypeError: Cannot read property 'componentWillAppear' of undefined
That's getting raised, because this.refs
is an empty object. (key
is correct).
Notably, if I close Chrome debugger so that the error is skipped, the site still works fine.
Our solution was to create a function that returned another function that in turn returned the component wrapped in a ReactTransitionGroup
.
var transitionWrap = (component, myKey) => {
return () => {
return (
<ReactTransitionGroup>
{ React.createElement(component, { key: myKey } ) }
</ReactTransitionGroup>
)
}
}
const routeConfig = [
{
path: "/",
component: AppContainer,
childRoutes: [
{ path: "/signed-out",
component: LoggedOut,
childRoutes: [
{ path: "/home", component: transitionWrap(Home, browserHistory.createKey()) }
]
}
]
}
];
ReactDOM.render(
<div>
<Provider store={store}>
<Router history={browserHistory} routes={routeConfig} />
</Provider>
</div>,
document.getElementById('app')
);
Works perfectly (giving the component access to Transition Group methods), with one exception -- the child component (ie Home
) cannot be connect
ed to Redux global state. If it needs to be, that component can essentially just be a wrapper that renders another component that connects to Redux state, so that Home
(for example) is really just there to handle animations, and its child component takes care of everything data-related.