如果导航到新路径,则更改 React 状态
Change React State if Navigating to New Path
我正在尝试实现 react-transition-group
,并且需要能够将 fadeEffectVisible
的状态从 false
更改为 true
假设用户的路径正在导航到与当前路径不同。换句话说,如果用户从 page-1
导航到 page-2
,但如果用户在 page-1
上并单击 link 到 page-1
,它应该可以工作。我正在使用挂钩和功能组件,这是我现在的 AppLayout
组件。
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>
</>
)}
/>
);
};
我在这里走上正确的道路了吗?谢谢!
我会使用另一种方法使用 useRef
挂钩来存储上一个页面路径(存储在 useState
中)并在它们之间进行比较。
创建自定义挂钩,如:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
并在您的组件中添加以下行:
const [page, setPage] = useState(location.pathname);
const prevPage = usePrevious(page) // <-- look here for your previous page
之后只需要比较location.pathname !== prevPage
.
location
prop
是 Gatsby 公开的 prop
(因为它从 React 的 @reach/router
扩展而来)仅在 top-level 组件(页面)中.可能 pathname
属性 不完全符合您的需求,检查一下以找出哪个 属性 符合您的要求。
参考文献:
由于 Ferran 的回答提供的大量帮助,我明白了这一点,但我想分享我的完整组件,因为我已经开始工作了。具体来说,这就是我如何设置它以正确更新我的 page
状态,并对照目标检查之前的 url
。
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>
</>
)}
/>
);
};
我正在尝试实现 react-transition-group
,并且需要能够将 fadeEffectVisible
的状态从 false
更改为 true
假设用户的路径正在导航到与当前路径不同。换句话说,如果用户从 page-1
导航到 page-2
,但如果用户在 page-1
上并单击 link 到 page-1
,它应该可以工作。我正在使用挂钩和功能组件,这是我现在的 AppLayout
组件。
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>
</>
)}
/>
);
};
我在这里走上正确的道路了吗?谢谢!
我会使用另一种方法使用 useRef
挂钩来存储上一个页面路径(存储在 useState
中)并在它们之间进行比较。
创建自定义挂钩,如:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
并在您的组件中添加以下行:
const [page, setPage] = useState(location.pathname);
const prevPage = usePrevious(page) // <-- look here for your previous page
之后只需要比较location.pathname !== prevPage
.
location
prop
是 Gatsby 公开的 prop
(因为它从 React 的 @reach/router
扩展而来)仅在 top-level 组件(页面)中.可能 pathname
属性 不完全符合您的需求,检查一下以找出哪个 属性 符合您的要求。
参考文献:
由于 Ferran 的回答提供的大量帮助,我明白了这一点,但我想分享我的完整组件,因为我已经开始工作了。具体来说,这就是我如何设置它以正确更新我的 page
状态,并对照目标检查之前的 url
。
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>
</>
)}
/>
);
};