react-router 在每次转换时滚动到顶部

IT技术 javascript reactjs react-router react-router-redux
2021-02-02 01:05:51

导航到另一个页面时遇到问题,它的位置将保持与之前的页面一样。所以它不会自动滚动到顶部。我也试过window.scrollTo(0, 0)onChange路由器上使用我也曾经scrollBehavior解决过这个问题,但没有用。对此有何建议?

6个回答

但课程是如此 2018

使用 React Hooks 实现 ScrollToTop

滚动到顶部.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);

用法:

<Router>
  <Fragment>
    <ScrollToTop />
    <Switch>
        <Route path="/" exact component={Home} />
    </Switch>
  </Fragment>
</Router>

ScrollToTop 也可以实现为一个包装组件:

滚动到顶部.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);

用法:

<Router>
  <ScrollToTop>
    <Switch>
        <Route path="/" exact component={Home} />
    </Switch>
  </ScrollToTop>
</Router>
此外,您可以只使用 useHistory 钩子而不是 withRouter HOC
2021-03-25 01:05:51
对于 TypeScript 用户,正确的historyprop类型History来自import { History } from "history";
2021-03-25 01:05:51
我需要添加history到 useEffect 的依赖项列表中
2021-03-27 01:05:51
你应该检查一下action !== 'POP'侦听器接受动作作为第二个参数
2021-03-28 01:05:51
迄今为止我在互联网上看到的最佳解决方案。我只是有点困惑为什么 react-router 项目没有scrollToTop<Route>. 它似乎是非常常用的功能。
2021-03-29 01:05:51

此答案仅适用于 v4,不适用于更高版本。

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)

然后在你的应用程序顶部渲染它,但在路由器下面:

const App = () => (
  <Router>
    <ScrollToTop>
      <App/>
    </ScrollToTop>
  </Router>
)

// or just render it bare anywhere you want, but just one :)
<ScrollToTop/>

^ 直接从文档中复制

显然这适用于大多数情况,但还有更多关于如何处理选项卡式界面以及为什么尚未实施通用解决方案的内容。

ScrollToTop 未定义。如何在 App.js 中导入它?从 './ScrollToTop' 导入 ScrollToTop 不起作用。
2021-03-24 01:05:51
您还应该在滚动到顶部的同时重置键盘焦点。我写了一个东西来照顾它:github.com/oaf-project/oaf-react-router
2021-03-26 01:05:51
这个来自文档的摘录Because browsers are starting to handle the “default case” and apps have varying scrolling needs (like this website!), we don’t ship with default scroll management. This guide should help you implement whatever scrolling needs you have.让我感到难过,因为他们继续提供代码示例的所有选项实际上都可以通过属性设置嵌入到控件中,然后可以更改一些有关默认行为的约定。这感觉超级hacky和未完成,恕我直言。意味着只有高级反应开发人员才能正确进行路由,而没有#pitOfSuccess
2021-04-02 01:05:51
你应该检查一下action !== 'POP'侦听器接受动作作为第二个参数
2021-04-06 01:05:51
oaf-react-router 似乎解决了work-arounds这里所有人都忽略的重要可访问性问题+100 @danielnixon
2021-04-10 01:05:51

react 16.8+

如果您正在运行 React 16.8+,这很容易使用一个组件来处理,该组件将在每次导航时向上滚动窗口:
这是在 scrollToTop.js 组件中

import { useEffect } from "react";
import { useLocation } from "react-router-dom";

export default function ScrollToTop() {
  const { pathname } = useLocation();

  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return null;
}

然后在你的应用程序顶部渲染它,但在路由器
下面是在 app.js 中

import ScrollToTop from "./scrollToTop";

function App() {
  return (
    <Router>
      <ScrollToTop />
      <App />
    </Router>
  );
}

或者在 index.js 中

import ScrollToTop from "./scrollToTop";

ReactDOM.render(
    <BrowserRouter>
        <ScrollToTop />
        <App />
    </BrowserRouter>
    document.getElementById("root")
);
谢谢,这是我认为最好的解决方案!
2021-03-14 01:05:51
是的,这是合适的解决方案,适用于使用钩子的 React 应用程序。
2021-03-22 01:05:51
这以前对我有用,但它已停止工作。有谁知道为什么?我什至没有更新反应路由器!先感谢您
2021-04-10 01:05:51

此答案适用于遗留代码,适用于路由器 v4+ 检查其他答案

<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
  ...
</Router>

如果它不起作用,您应该找到原因。还有里面componentDidMount

document.body.scrollTop = 0;
// or
window.scrollTo(0,0);

你可以使用:

componentDidUpdate() {
  window.scrollTo(0,0);
}

你可以添加一些像“scrolled = false”这样的标志,然后在更新中:

componentDidUpdate() {
  if(this.scrolled === false){
    window.scrollTo(0,0);
    scrolled = true;
  }
}
@MattVoda 在下面写了一个关于如何使用 react-router-v4 实现的答案
2021-03-21 01:05:51
onUpdate 在 react-router v4 中不推荐使用钩子 - 只是想指出这一点
2021-03-26 01:05:51
@DragosRizescu 关于在没有onUpdate钩子的情况下使用此方法的任何指导
2021-03-26 01:05:51
我已经更新了没有 getDomNode 的答案,因为事实上我从来没有使用它滚动到顶部。我刚用window.scrollTo(0,0);
2021-04-03 01:05:51
@MattVoda 您可以监听历史本身的变化,查看示例:github.com/ReactTraining/history
2021-04-07 01:05:51

您可以添加到 Route 组件的 React Hook。使用useLayoutEffect而不是自定义侦听器。

import React, { useLayoutEffect } from 'react';
import { Switch, Route, useLocation } from 'react-router-dom';

export default function Routes() {
  const location = useLocation();
  // Scroll to top if path changes
  useLayoutEffect(() => {
    window.scrollTo(0, 0);
  }, [location.pathname]);

  return (
      <Switch>
        <Route exact path="/">

        </Route>
      </Switch>
  );
}

更新:更新为使用useLayoutEffect而不是useEffect,以减少视觉卡顿。这大致翻译为:

  • useEffect: 渲染组件 -> 绘制到屏幕 -> 滚动到顶部(运行效果)
  • useLayoutEffect: 渲染组件 -> 滚动到顶部(运行效果) -> 绘制到屏幕

取决于您是否正在加载数据(想想微调器)或者您是否有页面过渡动画,useEffect可能更适合您。