I am trying to implement react-transition-group
, and need to be able to change a state of fadeEffectVisible
from false
to true
assuming that the path that a user is navigating to is not the same as the current path. In other words, it should work if a user navigates from page-1
to page-2
but not if a user is on page-1
and clicks a link to page-1
. I'm using hooks and functional components, and this is my AppLayout
component as it stands right now.
import React, { ReactNode, useEffect, useState } from 'react';
import { Footer } from 'components/footer/Footer';
import { Header } from 'components/header/Header';
import { NavigationSkipLink } from 'components/navigation-skip-link/NavigationSkipLink';
import { AppContext } from 'contexts/app-context/AppContext';
import { graphql, StaticQuery } from 'gatsby';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import s from './AppLayout.scss';
interface AppLayoutProps {
children: ReactNode;
location: any;
}
export const MainContentId = 'maincontent';
const NavQuery = graphql`
query NavQuery {
prismic {
allNavigations {
edges {
node {
...NotificationBar
...NavigationItems
...FooterNavigationItems
...LegalNavigationItems
}
}
}
}
}
`;
// eslint-disable-next-line react/display-name
export default ({ children, location }: AppLayoutProps) => {
const prevPath = location.href;
const [fadeEffectVisible, setfadeEffectVisible] = useState(true);
const handleFadeEffectEntered = () => {
setTimeout(() => {
setfadeEffectVisible(false);
}, 50);
};
useEffect(() => {
if (prevPath !== path) {
setfadeEffectVisible(true);
} else {
setfadeEffectVisible(false);
}
}, [path]);
return (
<StaticQuery
query={`${NavQuery}`}
render={(data) => (
<>
<AppContext>
<NavigationSkipLink />
<Header navigationContent={data.prismic.allNavigations.edges[0].node} />
<CSSTransition
in={fadeEffectVisible}
timeout={150}
classNames={{
enter: s.fadeEffectEnter,
enterActive: s.fadeEffectEnterActive,
enterDone: s.fadeEffectEnterDone,
exit: s.fadeEffectExit,
exitActive: s.fadeEffectExitActive,
}}
onEntered={handleFadeEffectEntered}
>
<div className={s.fadeEffect} aria-hidden="true" />
</CSSTransition>
<TransitionGroup component={null}>
<CSSTransition
key={path}
timeout={150}
classNames={{
enter: s.pageEnter,
}}
>
<div id={MainContentId} className={s.layout}>
{children}
<Footer navigationItems={data.prismic.allNavigations.edges[0].node} />
</div>
</CSSTransition>
</TransitionGroup>
</AppContext>
</>
)}
/>
);
};
Am I even close to being on the right path here? Thanks!
Figured this out, thanks to a great deal of help from Ferran's answer, but I wanted to share my full component now that I've got it working. Specifically, this is how I got it set up to correctly update my page
state, and check the previous url
against the target.
const [page, setPage] = useState(pathname);
const prevPage = usePrevious(pathname);
useEffect(() => {
if (pathname !== prevPage) {
setFadeEffectVisible(true);
setPage(page);
}
}, [pathname]);
AppLayout.tsx
import React, { ReactNode, useEffect, useState } from 'react';
import { Devtools } from 'components/devtools/Devtools';
import { Footer } from 'components/footer/Footer';
import { Header } from 'components/header/Header';
import { NavigationSkipLink } from 'components/navigation-skip-link/NavigationSkipLink';
import { AppContext } from 'contexts/app-context/AppContext';
import { graphql, StaticQuery } from 'gatsby';
import { usePrevious } from 'hooks/use-previous';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import s from './AppLayout.scss';
interface AppLayoutProps {
props: any;
children: ReactNode;
location: any;
}
const isDev = process.env.NODE_ENV === 'development';
export const MainContentId = 'maincontent';
const NavQuery = graphql`
query NavQuery {
prismic {
allNavigations {
edges {
node {
...NotificationBar
...NavigationItems
...FooterNavigationItems
...LegalNavigationItems
}
}
}
}
}
`;
// eslint-disable-next-line react/display-name
export default ({ children, location: { pathname } }: AppLayoutProps) => {
const [fadeEffectVisible, setFadeEffectVisible] = useState(false);
const [page, setPage] = useState(pathname);
const prevPage = usePrevious(pathname);
const timeout = 250;
useEffect(() => {
if (pathname !== prevPage) {
setFadeEffectVisible(true);
setPage(page);
}
}, [pathname]);
console.log(prevPage);
const handleFadeEffectEntered = () => {
setTimeout(() => {
setFadeEffectVisible(false);
}, 50);
};
return (
<StaticQuery
query={`${NavQuery}`}
render={(data) => (
<>
<AppContext>
<CSSTransition
in={fadeEffectVisible}
timeout={timeout}
classNames={{
enter: s.fadeEffectEnter,
enterActive: s.fadeEffectEnterActive,
enterDone: s.fadeEffectEnterDone,
exit: s.fadeEffectExit,
exitActive: s.fadeEffectExitActive,
}}
onEntered={handleFadeEffectEntered}
>
<div className={s.fadeEffect} aria-hidden="true" />
</CSSTransition>
<NavigationSkipLink />
<Header navigationContent={data.prismic.allNavigations.edges[0].node} />
<TransitionGroup component={null}>
<CSSTransition
key={pathname}
timeout={timeout}
classNames={{
enter: s.pageEnter,
}}
>
<div id={MainContentId} className={s.layout}>
{children}
<Footer navigationItems={data.prismic.allNavigations.edges[0].node} />
{isDev && <Devtools />}
</div>
</CSSTransition>
</TransitionGroup>
</AppContext>
</>
)}
/>
);
};