Javascript react-router 在每次转换时滚动到顶部
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36904185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
react-router scroll to top on every transition
提问by adrian hartanto
I have an issue when navigating into another page, its position will remain like the page before. So it wont scroll to top automatically.
I've also tried to use window.scrollTo(0, 0)
on onChange router. I've also used scrollBehavior to fix this issue but it didnt work. Any suggestion about this?
我在导航到另一个页面时遇到问题,它的位置将保持与之前的页面一样。所以它不会自动滚动到顶部。我也尝试window.scrollTo(0, 0)
在 onChange 路由器上使用。我也使用 scrollBehavior 来解决这个问题,但它没有用。对此有何建议?
回答by mtl
The documentation for React Router v4 contains code samplesfor scroll restoration. Here is their first code sample, which serves as a site-wide solution for “scroll to the top” when a page is navigated to:
React Router v4 的文档包含滚动恢复的代码示例。这是他们的第一个代码示例,当页面被导航到时,它作为“滚动到顶部”的站点范围的解决方案:
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop)
Then render it at the top of your app, but below Router:
然后在你的应用程序顶部渲染它,但在路由器下面:
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
// or just render it bare anywhere you want, but just one :)
<ScrollToTop/>
^ copied directly from the documentation
Obviously this works for most cases, but there is more on how to deal with tabbed interfaces and why a generic solution hasn't been implemented.
显然这适用于大多数情况,但还有更多关于如何处理选项卡式界面以及为什么尚未实施通用解决方案的内容。
回答by zurfyx
but classes are so 2018
但课程是如此 2018
ScrollToTop implementation with React Hooks
使用 React Hooks 实现 ScrollToTop
ScrollToTop.js
滚动到顶部.js
import { useEffect } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
return (null);
}
export default withRouter(ScrollToTop);
Usage:
用法:
<Router>
<Fragment>
<ScrollToTop />
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</Fragment>
</Router>
ScrollToTop can also be implemented as a wrapper component:
ScrollToTop 也可以实现为一个包装组件:
ScrollToTop.js
滚动到顶部.js
import React, { useEffect, Fragment } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history, children }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
return <Fragment>{children}</Fragment>;
}
export default withRouter(ScrollToTop);
Usage:
用法:
<Router>
<ScrollToTop>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</ScrollToTop>
</Router>
回答by Lukas Liesis
This answer is for legacy code, for router v4+ check other answers
此答案适用于遗留代码,适用于路由器 v4+ 检查其他答案
<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
...
</Router>
If it's not working, you should find the reason. Also inside componentDidMount
如果它不起作用,您应该找到原因。还有里面componentDidMount
document.body.scrollTop = 0;
// or
window.scrollTo(0,0);
you could use:
你可以使用:
componentDidUpdate() {
window.scrollTo(0,0);
}
you could add some flag like "scrolled = false" and then in update:
你可以添加一些像“scrolled = false”这样的标志,然后在更新中:
componentDidUpdate() {
if(this.scrolled === false){
window.scrollTo(0,0);
scrolled = true;
}
}
回答by Dragos Rizescu
For react-router v4, here is a create-react-app that achieves the scroll restoration: http://router-scroll-top.surge.sh/.
对于react-router v4,这是一个实现滚动恢复的 create-react-app:http://router-scroll-top.surge.sh/。
To achieve this you can create decorate the Route
component and leverage lifecycle methods:
为此,您可以创建装饰Route
组件并利用生命周期方法:
import React, { Component } from 'react';
import { Route, withRouter } from 'react-router-dom';
class ScrollToTopRoute extends Component {
componentDidUpdate(prevProps) {
if (this.props.path === this.props.location.pathname && this.props.location.pathname !== prevProps.location.pathname) {
window.scrollTo(0, 0)
}
}
render() {
const { component: Component, ...rest } = this.props;
return <Route {...rest} render={props => (<Component {...props} />)} />;
}
}
export default withRouter(ScrollToTopRoute);
On the componentDidUpdate
we can check when the location pathname changes and match it to the path
prop and, if those satisfied, restore the window scroll.
在componentDidUpdate
我们可以检查位置路径发生变化时,它匹配的path
道具,如果那些满足,恢复窗口滚动。
What is cool about this approach, is that we can have routes that restore scroll and routes that don't restore scroll.
这种方法很酷的是,我们可以拥有恢复滚动的路由和不恢复滚动的路由。
Here is an App.js
example of how you can use the above:
以下是App.js
如何使用上述内容的示例:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Lorem from 'react-lorem-component';
import ScrollToTopRoute from './ScrollToTopRoute';
import './App.css';
const Home = () => (
<div className="App-page">
<h2>Home</h2>
<Lorem count={12} seed={12} />
</div>
);
const About = () => (
<div className="App-page">
<h2>About</h2>
<Lorem count={30} seed={4} />
</div>
);
const AnotherPage = () => (
<div className="App-page">
<h2>This is just Another Page</h2>
<Lorem count={12} seed={45} />
</div>
);
class App extends Component {
render() {
return (
<Router>
<div className="App">
<div className="App-header">
<ul className="App-nav">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/another-page">Another Page</Link></li>
</ul>
</div>
<Route exact path="/" component={Home} />
<ScrollToTopRoute path="/about" component={About} />
<ScrollToTopRoute path="/another-page" component={AnotherPage} />
</div>
</Router>
);
}
}
export default App;
From the code above, what is interesting to point out is that only when navigating to /about
or /another-page
the scroll to top action will be preformed. However when going on /
no scroll restore will happen.
从上面的代码中,有趣的是,只有在导航到/about
或/another-page
滚动到顶部动作时才会执行。但是,在进行时/
不会发生滚动恢复。
The whole codebase can be found here: https://github.com/rizedr/react-router-scroll-top
整个代码库可以在这里找到:https: //github.com/rizedr/react-router-scroll-top
回答by Harry Le
It is noteable that the onUpdate={() => window.scrollTo(0, 0)}
method is outdated.
值得注意的是,该onUpdate={() => window.scrollTo(0, 0)}
方法已经过时。
Here is a simple solution for react-router 4+.
这是 react-router 4+ 的简单解决方案。
const history = createBrowserHistory()
history.listen(_ => {
window.scrollTo(0, 0)
})
<Router history={history}>
回答by Jhalaa Chinoy
I had the same issue with my application.Using the below code snippet helped me scroll to the top of the page on click of the next button.
我的应用程序遇到了同样的问题。使用下面的代码片段帮助我在单击下一个按钮时滚动到页面顶部。
<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}>
...
</Router>
However, the issue still persisted on browser back. After a lot of trials, realized that this was because of the browser window's history object, which has a property scrollRestoration which was set to auto.Setting this to manual solved my problem.
但是,问题仍然存在于浏览器后面。经过大量试验,意识到这是因为浏览器窗口的历史对象,它有一个属性 scrollRestoration 被设置为 auto.Setting this to manual 解决了我的问题。
function scrollToTop() {
window.scrollTo(0, 0)
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
}
<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>
回答by Thomas Aumaitre
In a component below <Router>
在下面的组件中 <Router>
Just add a React Hook (in case you are not using a React class)
只需添加一个 React Hook(以防您不使用 React 类)
React.useEffect(() => {
window.scrollTo(0, 0);
}, [props.location]);
回答by Luis Febro
I want to share my solution for those who are using react-router-dom v5
since none of these v4 solutions did the work for me.
我想为那些正在使用的人分享我的解决方案,react-router-dom v5
因为这些 v4 解决方案都没有为我工作。
What solved my problem was installing react-router-scroll-topand put the wrapper in the <App />
like this:
解决我的问题的是安装react-router-scroll-top并将包装器放在<App />
这样的位置:
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
and that's it! it worked!
就是这样!有效!
回答by Kris Dover
Hooks are composable, and since React Router v5.1 we have a useHistory()
hook. So based off @zurfyx's answer I've created a re-usable hook for this functionality:
钩子是可组合的,从 React Router v5.1 开始,我们有了一个useHistory()
钩子。因此,基于@zurfyx 的回答,我为此功能创建了一个可重复使用的钩子:
// useScrollTop.ts
import { useHistory } from 'react-router-dom';
import { useEffect } from 'react';
/*
* Registers a history listener on mount which
* scrolls to the top of the page on route change
*/
export const useScrollTop = () => {
const history = useHistory();
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return unlisten;
}, [history]);
};
回答by Yangshun Tay
I wrote a Higher-Order Component called withScrollToTop
. This HOC takes in two flags:
我编写了一个名为withScrollToTop
. 这个 HOC 有两个标志:
onComponentWillMount
- Whether to scroll to top upon navigation (componentWillMount
)onComponentDidUpdate
- Whether to scroll to top upon update (componentDidUpdate
). This flag is necessary in cases where the component is not unmounted but a navigation event occurs, for example, from/users/1
to/users/2
.
onComponentWillMount
- 导航时是否滚动到顶部 (componentWillMount
)onComponentDidUpdate
- 更新时是否滚动到顶部 (componentDidUpdate
)。在组件未卸载但发生导航事件(例如 from/users/1
to )的情况下,此标志是必需的/users/2
。
// @flow
import type { Location } from 'react-router-dom';
import type { ComponentType } from 'react';
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
type Props = {
location: Location,
};
type Options = {
onComponentWillMount?: boolean,
onComponentDidUpdate?: boolean,
};
const defaultOptions: Options = {
onComponentWillMount: true,
onComponentDidUpdate: true,
};
function scrollToTop() {
window.scrollTo(0, 0);
}
const withScrollToTop = (WrappedComponent: ComponentType, options: Options = defaultOptions) => {
return class withScrollToTopComponent extends Component<Props> {
props: Props;
componentWillMount() {
if (options.onComponentWillMount) {
scrollToTop();
}
}
componentDidUpdate(prevProps: Props) {
if (options.onComponentDidUpdate &&
this.props.location.pathname !== prevProps.location.pathname) {
scrollToTop();
}
}
render() {
return <WrappedComponent {...this.props} />;
}
};
};
export default (WrappedComponent: ComponentType, options?: Options) => {
return withRouter(withScrollToTop(WrappedComponent, options));
};
To use it:
要使用它:
import withScrollToTop from './withScrollToTop';
function MyComponent() { ... }
export default withScrollToTop(MyComponent);