Open j2is opened 4 years ago
@j2is I managed to do this with https://github.com/reactjs/react-transition-group instead
@mattjis Do you have an example by chance?
import React, { useRef, useState, useEffect } from 'react';
import { CSSTransition } from 'react-transition-group';
import { useRouter } from 'next/router';
import './app.css';
function PageTransition(props) {
const { c: PageComponent, lc: lastPageComponent } = props;
const componentsDiffer = lastPageComponent &&
PageComponent.key !== lastPageComponent.key;
const [transitioning, setTransitioning] = useState(componentsDiffer); // Transition if components differ
const [transitioningFor, setTransitioningFor] = useState(PageComponent.key); // Keep track of which we just transitioned in
// If the components differ and PageComponent.key is new, we need to start
// a new transition
if (componentsDiffer &&
transitioningFor !== PageComponent.key) {
setTransitioningFor(PageComponent.key);
setTransitioning(true);
}
function onFinishTransition() {
console.log('FINISHED', PageComponent.key);
setTransitioning(false);
}
function fixScroll() {
// Scroll left to 0 every frame, firefox will fuck this up if not
document.querySelector('.concerning').scrollLeft = 0;
}
console.log(PageComponent?.key, lastPageComponent?.key, transitioning, transitioningFor);
return (
<div className='concerning'>
<CSSTransition in={!transitioning} appear={true} timeout={600} classNames="page-transition" exit={false} onExited={onFinishTransition}>
<div>
{PageComponent}
</div>
</CSSTransition>
<CSSTransition in={transitioning} timeout={600} classNames="page-transition" enter={false} onExiting={fixScroll} onExited={onFinishTransition}>
<div className="outgoing">
{lastPageComponent}
</div>
</CSSTransition>
</div>
);
}
export default function MyApp(params) {
const router = useRouter();
const key = router.route;
const { Component: PageComponent, pageProps } = params;
// Needs to be in MyApp, otherwise it will get recreated with a new page when the page changes and then we lose the last component
// If you useState, react throws lots of out of order hook errors, cant store JSX inside state
const lastPageComponentRef = useRef(undefined);
const getLayoutAndPage = (PageComponent, pageProps) => {
// TODO: Convert this into just one function
// Use the layout defined at the page level, if available
const getLayout = PageComponent.getLayout || ((page) => page);
// Use the layout builder defined (which takes pageComponent and pageProps and builds the
// pageComponent too
const getLayoutBuilder = PageComponent.getLayoutBuilder || ((PageComponent, pageProps) => getLayout(<PageComponent {...pageProps} />));
return (
<div key={key}>
{getLayoutBuilder(PageComponent, pageProps)}
</div>
);
};
const c = getLayoutAndPage(PageComponent, pageProps);
const lc = lastPageComponentRef.current || getLayoutAndPage(PageComponent, pageProps);
const ret = (
<PageTransition lc={lastPageComponentRef.current} c={getLayoutAndPage(PageComponent, pageProps)} />
);
lastPageComponentRef.current = c;
return ret;
}
.concerning {
position: relative;
width: 100%;
overflow: hidden;
}
.page-transition-enter-done,
.page-transition-appear-done,
.page-transition-exit-done {
}
.page-transition-enter {
transform: translateX(-100%);
}
.page-transition-enter-active {
transform: translate(0);
transition: transform 600ms;
transition-timing-function: cubic-bezier(.26,1,.25,1);
}
.page-transition-exit {
display: block !important;
transform: translate(0);
}
.page-transition-exit-active {
display: block !important;
transform: translateX(100%);
transition: transform 600ms;
transition-timing-function: cubic-bezier(.26,1,.25,1);
}
.page-transition-exit-done {
display: none;
}
.outgoing {
position: absolute;
top: 0;
left: 0;
width: 100%;
pointer-events: none;
}
Rough code for anyone who needs it. This implements sliding pages in Next at the _app.js level. Things that I learned:
in
was tough, because it needs to be true when the component changes up until the point that the transition ends. Then it needs to be flipped back so the next transition works (also why we disable exit and enter)
All examples have one page shown at a time, is it possible to have the previous page visible while the new one transitions in? (Like the Instagram app)