我有一个简单的页面转换,它在单击链接时被调用。新页面从屏幕底部向上到顶部设置动画。它工作得很好,但当你在浏览器中单击后退按钮时,它也能工作。如果有人点击浏览器上的后退按钮,我不希望转换启动,我只想回到我留下的任何滚动位置的页面,就像点击浏览器后退按钮一样。
如果我去掉了CSS转换,那么后退按钮就可以正常工作,所以我需要以某种方式区分被点击的后退按钮和被点击的链接,然后相应地播放转换。
我不知道我是需要设置State还是其他什么?我确实尝试过,但它似乎在转换发生后设置了状态变量。
import React, { useEffect, useState } from 'react';
import {Route, NavLink, Switch, useHistory } from "react-router-dom";
import './App.css';
import Home from './Home';
import About from './About';
import { CSSTransition, TransitionGroup,} from 'react-transition-group';
const usePageMeta = (title, description) =>{
const defaultTitle = "app-name";
const defaultDesc = "meta description";
useEffect(() => {
document.title = title || defaultTitle;
document.querySelector("meta[name='description']").setAttribute("content", description || defaultDesc);
}, [defaultTitl
e, title, defaultDesc, description]);
};
const App = () =>{
return (
<div className="App">
<div className="nav fixed top-0 left-0 z-10 w-full">
<NavLink exact to="/" activeClassName="active">Home</NavLink>
<NavLink to="/about" activeClassName="active">About</NavLink>
</div>
<Route render={({location}) => (
<TransitionGroup>
<CSSTransition
key={location.key}
timeout={1000}
classNames="fade"
>
<Switch location={location}>
<Route exact path="/">
<Home usePageMeta={usePageMeta}/>
</Route>
<Route path="/about">
<About usePageMeta={usePageMeta}/>
</Route>
</Switch>
</CSSTransition>
</TransitionGroup>
)} />
</div>
);
}
export default App;
有人能给我指正确的方向吗?
经过一些测试,我可以看到,当路径被加载到浏览器的历史记录中时,这种情况必然会发生。
tl;dr这不是库的怪癖,只是浏览器的工作方式。当前会话总是在历史对象上推送状态。为了防止这种情况,你可以做两件事
- 每当用户导航到新路径时,覆盖历史状态
- 阻止后退按钮的默认操作并重定向到入口网站
解决方案1:
- 从"history"包导入createBrowserHistory,并在应用程序组件外部创建一个可变的history
- 使用
history.createHref(history.location)
进入应用程序时,使启动状态的字符串不可变 - 定义一个onClick处理程序,将历史记录的顶部状态替换为当前位置
- 使用上面定义的函数在两个NavLinks上注册一个点击处理程序
- 在历史记录中添加一个监听器(history.listen(,如果操作是pop,则调用history.goBack((
- 在卸载时调用unlisten
import { createBrowserHistory } from 'history';
let history = createBrowserHistory();
const ContainerComponent = () => {
// removed uselocation and usehistory hooks
const location = history.createHref(history.location);
const replaceHistory = () => {
history.replace(location);
}
const unlisten = history.listen((location, action) => {
if (action == "POP")
history.goBack();
})
useEffect(() => {
return () => unlisten();
})
return (
<div>
<Navlink to='/' onClick={replaceHistory} />
<Navlink to='/about' onClick={replaceHistory} />
</div>
);
}
解决方案2:
- 从"history"模块导入createBrowserHistory,并在应用程序组件外部创建一个可变历史对象
- 将监听器添加到历史记录(history.listen(中,当它接收到"-";POP";行动
- 使用Effect"取消收听"此事件
注意:这是假设用户必须导航到来自的网站。
import { createBrowserHistory } from 'history';
// Creates a mutable history state.
let history = createBrowserHistory();
const ContainerComponent = () => {
//removed the eventlistener on window
const unlisten() = history.listen((location, action) => {
//remove the logging once satisfied with the result.
console.log(`${location}, ${action}`);
if ( action == "POP" ) {
history.goBack();
}
})
// removed 'popstate' evenhandler
// adding useEffect to call unlisten on unmount
useEffect (() => {
return () => unlisten();
}, [])
const count = () => {
setPageChanges(pageChanges + 1);
}
return (
<div>
<NavLink to='/' onClick={count} />
<NavLink to='/about' onClick={count} />
</div>
{/*... rest of the switch code with the transition ...*/}
);
}
编辑:解决方案2被重构为使用"历史"包实用程序。这被认为是更合适的,因为浏览器状态不与react代码接触。
同样在文档中,提到历史对象是可变的,这确实会导致安装方面的一些问题。
注意:这个解决方案会遍历用户所在位置和开始位置之间的所有状态,所以可以期待早期组件的一些闪光。
解决方案1也使用相同的包,但需要注意的是,它将转到第一页,然后再转到goBack((1页。这将是比解决方案2更少的闪光。