реагировать-роутер прокручивается вверх на каждый переход

У меня проблема при переходе на другую страницу, ее позиция останется прежней. Таким образом, он не будет автоматически прокручиваться вверх. Я также пытался использоватьwindow.scrollTo(0, 0)<<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}> ... </Router>code> on onChange componentDidMountr. I've also used scrollBehavior to fix this issue but it didnt work. Any suggestion about this?

javascript,reactjs,react-router,react-router-redux,

19

Ответов: 9


20

This answer is for legacy code, for router v4+ check other answers

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

If it's not working, you should find the reason. Also inside componentDidUpdate() { window.scrollTo(0,0); }

componentDidUpdate() {
  if(this.scrolled === false){
    window.scrollTo(0,0);
    scrolled = true;
  }
}

you could use:

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)

you could add some flag like "scrolled = false" and then in update:

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

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

18

The documentation for React Router v4 contains code samples for scroll restoration. Here is their first code sample, which serves as a site-wide solution for a€?scroll to the topa€? when a page is navigated to:

Route

Then render it at the top of your app, but below Router:

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);

^ 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.


17

For react-router v4, here is a create-react-app that achieves the scroll restoration: http://router-scroll-top.surge.sh/.

To achieve this you can create decorate the Route component and leverage lifecycle methods:

componentDidUpdate

On the path we can check when the location App.jsname changes and match it to the path prop and, if those satisfied, restore the window scroll.

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 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; example of how you can use the above:

/about

From the code above, what is interesting to point out is that only when navigating to /another-page or / the scroll to top action will be preformed. However when going on / no scroll restore will happen.

The whole codebase can be found here: https://github.com/rizedr/react-router-scroll-top


5

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.

function scrollToTop() {
    window.scrollTo(0, 0)
    if ('scrollRestoration' in history) {
        history.scrollRestoration = 'manual';
    }
}

<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>

2

I wrote a Higher-Order Component called withScrollToTop. This HOC takes in two flags:

  • 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.

// @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);
javascript,reactjs,react-router,react-router-redux,
Похожие вопросы