Open <Link> at top of page

Viewed 17059

I'm using React Router 4 and when I use <Link> the new page doesn't open at the top of the page. Do I need to tell <Link> something specific?

<Link to="/mypage">My Page</Link>
5 Answers

I know my answer might be similar as previous but I just want to help those who are using React Hooks and might come across this question/answers...

useLayoutEffect(() => {
    window.scrollTo(0, 0)
});

Basically, what I mean is that, add window.scrollTo(0, 0) inside the useLayoutEffect and will work fine.

I found a pretty solid answer for this in the answer to a similar question. It worked for me anyway so I thought I would share.

For your situation, in the component for "/mypage" add window.scrollTo(0, 0); to the componentDidMount function. Something like this:

import ...
export default class MyPage extends Component {
    constructor(props) {
        super(props);

        this.state = {
            ...
        };
    }

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

    render() {
        return (
            ...
        )
    }
}

The Link component will handle navigating to the new path and once the new component is mounted, it will automatically scroll to the top.

To go back to the What I did is when my Compoenent inside my BrowserRouter Updates I send it back to the top with the window props like this :

Root.jsx :

...
    <BrowserRouter onUpdate={() => window.scrollTo(0, 0)} >
      <Switch>
        <Route exact path={path.LOGIN} render={Login} />
        <Route exact path={path.SIGNUP} render={Signup} />
        <Route
          path={path.HOMEPAGE}
          render={() => <HomePageRouter />}
        />
      </Switch>
    </BrowserRouter>
...

And Then in my HomePageRouter

class HomePageRouter extends Component {

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

  render() {
    return (
      <div className='bm-page-wrapper' >
        <NavBar
          activeItem={this.props.menu.activeItem}
          toggle={this.props.menu.toggle}
          lang={this.props.lang}
        />
        <Switch >
          <Route
            exact
            path={path.HOMEPAGE}
            render={() => <Homepage lang={this.props.lang} />}
          />
          <Route
            path={path.ABOUT}
            render={() => <About lang={this.props.lang} />}
          />
          <Route
            path={path.CONTACT}
            render={() => <Contact lang={this.props.lang} />}
          />
          <Route render={() => <NotFound lang={this.props.lang} />} />
        </Switch>
        <Footer lang={this.props.lang} />
      </div>
    );
  }
}

So any path that I go in my HomePageRouter component, it will detect a route update and will cause it to re render. I would recommand using some sub Router so you don't have to add componentDidUpdate(){...} on every component !

Hopes it helps !

v6: if you don't want to use a side effect you can do something like this

// ScrollLink.ts

import React from 'react';
import {Link, LinkProps} from "react-router-dom";

const ScrollLink = React.forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
  return <Link {...props} ref={ref} onClick={() => window.scrollTo(0, 0)}/>
});

export default ScrollLink;

and then use ScrollLink wherever you want to scroll on click

Related