Skip to content

Scroll to top on route change? #2019

@paOol

Description

@paOol

Trying to have the browser scroll to the top upon cliking a router . Curren't it is preserving the scroll position.

Could not find anywhere in the documentation.

my render looks something like this

React.render(
  <Router history={createBrowserHistory()} routes={routes} />,
  document.getElementById('root')
);

Activity

heyheyjp

heyheyjp commented on Sep 20, 2015

@heyheyjp

There's been a lot of discussion in previously filed (and closed) issues on the topic of scroll behavior with 1.0. Check it out! :)

https://github.com/rackt/react-router/issues?utf8=%E2%9C%93&q=is%3Aissue+scroll

LDMFD

LDMFD commented on Sep 22, 2015

@LDMFD

I'm on 1.0.0-rc1 and also need conventional browser scroll behaviour (preserve scroll position when using the back button, scroll up when you come to a new page).

Any chance you can give us an ETA for getting this into 1.0.0, or a quick-fix until? None of the closed issues matching 'scroll' give a hint..

VictorienTardif

VictorienTardif commented on Sep 29, 2015

@VictorienTardif

+1

jackmoore

jackmoore commented on Sep 30, 2015

@jackmoore

Use onUpdate, from #2144

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

nicolashery commented on Oct 25, 2015

@nicolashery

@darreng see my comment on implementing the behavior "preserve scroll position when using the back button, scroll up when you come to a new page" #2144 (comment)

DanielSundberg

DanielSundberg commented on Nov 4, 2015

@DanielSundberg

Is the onUpdate={() => window.scrollTo(0, 0)} and #2144 (comment) the proposed way to handle this in 1.0.0?

I have tried to read through all the issues but have not found anything that makes this clear.

kojuka

kojuka commented on Nov 7, 2015

@kojuka

how do I get the current location in the onUpdate() function?

jackmoore

jackmoore commented on Nov 8, 2015

@jackmoore

@webular I don't think you can. I had the same need and switched from using onUpdate to history's listen method (first argument is the location object): https://github.com/rackt/history/blob/master/docs/GettingStarted.md

kojuka

kojuka commented on Nov 16, 2015

@kojuka
mikestopcontinues

mikestopcontinues commented on Dec 9, 2015

@mikestopcontinues

@webular if you're looking to preserve scroll depth for the back button, you can just use the window.location.

thedamon

thedamon commented on Jan 4, 2016

@thedamon

This really deserves a FAQ or a mention in the readme. I have read through a lot of issues and I have no idea what the current stance is on it.

added a commit that references this issue on Mar 25, 2016

33 remaining items

pedi

pedi commented on Apr 27, 2017

@pedi

@mmcgahan You solution won't work robustly

both the back and forward buttons in a web browser trigger a POP action

Let's say the navigation stack is
-> A -> B

Then we press go back, POP
-> A
navigate somewhere deep in page A

Then we press go forward, still POP action
-> A -> B
We will end up with some deep down in page B also

pedi

pedi commented on Apr 27, 2017

@pedi

Here's a naively implemented solution. It works for me so far.

Do note that there are browser discrepancies not handled (like browser fire on scroll event for push state change etc)

// @flow
import React, { Component, Children } from 'react';
import { withRouter } from 'react-router';
import type { Location, RouterHistory } from 'react-router';

type PropTypes = {
  location: Location,
  history: RouterHistory,
  children: any,
};

const PREFIX = '@@scroll/';

class ScrollBehavior extends Component {
  props: PropTypes;
  static locationVisited: {
    [key: string]: number,
  } = {};

  constructor(props: PropTypes) {
    super(props);
    (this: any).onScroll = this.onScroll.bind(this);
  }
  componentDidMount() {
    history.scrollRestoration = 'manual';
    window.addEventListener('scroll', this.onScroll);
  }

  componentWillUnmount() {
    history.scrollRestoration = 'auto';
    window.removeEventListener('scroll', this.onScroll);
  }

  onScroll() {
    requestAnimationFrame(() => {
      ScrollBehavior.locationVisited[this.getLocationKey(this.props.location.key)] = window.scrollY;
    });
  }

  getLocationKey(key) {
    return PREFIX + (key || '');
  }

  scrollTo(Y: number) {
    requestAnimationFrame(() => {
      window.scrollTo(0, Y);
    });
  }

  componentWillReceiveProps(nextProps: PropTypes) {
    const { location, history: { action } } = nextProps;
    if (location !== this.props.location) {
      if (action === 'PUSH') {
        // new navigation - scroll to top
        this.scrollTo(0);
      } else {
        const key = this.getLocationKey(location.key);
        if (ScrollBehavior.locationVisited.hasOwnProperty(key)) {
          const scrollY = ScrollBehavior.locationVisited[key];
          this.scrollTo(scrollY);
        }
      }
    }
  }

  render() {
    return Children.only(this.props.children);
  }
}

export default withRouter(ScrollBehavior);
vivmaha

vivmaha commented on May 5, 2017

@vivmaha

I ended up using the <ScrollToTop> workaround described in the react-router docs.

Here is my implementation, and an example usage (Typescript).

deleted a comment from wedelgaard on Nov 18, 2017
deleted a comment from Quernest on Jan 20, 2018
deleted a comment from nazreen on Jan 20, 2018
deleted a comment from beeant on Jan 20, 2018
deleted a comment from jameshiew on Jan 20, 2018
locked and limited conversation to collaborators on Jan 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @jackmoore@mikestopcontinues@kojuka@antipin@LDMFD

        Issue actions

          Scroll to top on route change? · Issue #2019 · remix-run/react-router