nareshbhatia / mobx-state-router

MobX-powered router for React apps
https://nareshbhatia.github.io/mobx-state-router/
MIT License
227 stars 30 forks source link

Animated page transition #50

Closed pvider closed 5 years ago

pvider commented 5 years ago

Before I've used React Router 4 with TransitionGroup and CSSTransition. Previous page were faded away and moved horizontally while new one appeared. Just translateX and opacity animation in css. How to achive same effect with mobx-state-router? When I try to put RouterView instead of ReactRouter4 Switch previous page instantly becomes new page and I see how same page disappears and appears. How to make it work? This is my code piece:

export default class Shell extends React.Component {
    render() {
        const { rootStore: { routerStore } } = this.props;
        const { routeName } = routerStore.routerState;
        console.warn(routeName)

        return (
            <div>
                <DevTools position={{ bottom: 0, right: 0 }} />
                <Header />
                <div style={{ margin: "0 auto", maxWidth: 1200, textOverflow: "hidden" }}>
                    <TransitionGroup>
                        <CSSTransition
                            key={routeName}
                            timeout={{ enter: 1200, exit: 1200 }}
                            classNames={'fade'}
                        >
                            <section className="route-section">
                                <RouterView routerStore={routerStore} viewMap={viewMap} />
                                <Footer />
                            </section>
                        </CSSTransition>
                    </TransitionGroup>
                </div>
            </div>
        );
    }
}
nareshbhatia commented 5 years ago

I figured out the issue, but don't have a solution yet. TransitionGroup holds on to the previous child and the new child and renders both during the timeout duration. In the code above, the previous child and the new child are both RouterViews - two different instances. Unfortunately both instances will render the new state because that's what RouterView is supposed to do! We need to figure out how to hold on to the previous view during the transition state.

Still thinking. Let me know if you have any ideas.

nareshbhatia commented 5 years ago

I wonder if we can use RouterStore.isTransitioning observable to do page transitions - maybe fade out the page when isTransitioning is true and fade in the new page when isTransitioning is false.

nareshbhatia commented 5 years ago

Ok, got it! Don't use RouterView. Do the determination of the view outside of the TransitionGroup. This will allow the TransitionGroup to hold on to the old view. Here's my code. Note that the class has to be an observer so that it can observe changes in RouterState:

const viewMap = {
    home: <HomePage />,
    about: <AboutPage />,
    notFound: <NotFoundPage />
};

export const Shell = inject('rootStore')(
    observer(
        class extends React.Component {
            render() {
                const { rootStore } = this.props;
                const { routerStore } = rootStore;
                const routeName = routerStore.routerState.routeName;
                const view = viewMap[routeName];

                return (
                    <React.Fragment>
                        <Header />
                        <div className="content-holder">
                            <TransitionGroup component={null}>
                                <CSSTransition
                                    key={routerStore.routerState.routeName}
                                    timeout={250}
                                    classNames="fade"
                                >
                                    {view}
                                </CSSTransition>
                            </TransitionGroup>
                        </div>
                    </React.Fragment>
                );
            }
        }
    )
);

I will post a full example by tomorrow.

nareshbhatia commented 5 years ago

Example published here.