react-router-hash-link icon indicating copy to clipboard operation
react-router-hash-link copied to clipboard

Doesn't scroll on reload / refresh

Open cjke opened this issue 7 years ago • 20 comments

Note This may be out of scope for this package.

Thanks for this package, I have been following this issue for quite a while.

The link works perfectly, however if a reload / refresh occurs, the page no longer scrolls down into position.

cjke avatar Jan 19 '18 04:01 cjke

Hi, I'm not able to reproduce this issue. When I go to http://react-router-hash-link.rafrex.com/bar#section-two and refresh in Chrome/Safari/Firefox is scrolls properly (the browser is handling the scroll in this case).

Do you have a failing example I can look at?

rafgraph avatar Jan 19 '18 04:01 rafgraph

Hmm cool. First thanks for responding so quickly.

Let me get an example together

On Fri, 19 Jan 2018 at 3:58 pm, Rafael Pedicini [email protected] wrote:

Hi, I'm not able to reproduce this issue. When I go to http://react-router-hash-link.rafrex.com/bar#section-two and refresh in Chrome/Safari/Firefox is scrolls properly (the browser is handling the scroll in this case).

Do you have a failing example I can look at?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rafrex/react-router-hash-link/issues/13#issuecomment-358866938, or mute the thread https://github.com/notifications/unsubscribe-auth/AA19YUijTvXzQy3rrtb91rMeb-por2QQks5tMCDvgaJpZM4Rj-Fg .

cjke avatar Jan 19 '18 04:01 cjke

Sorry my bad, it is working!

Cheers

cjke avatar Jan 19 '18 09:01 cjke

@cjke How did you get it to work? Having the same issue.

Ninjami-Juho avatar Feb 07 '18 20:02 Ninjami-Juho

Well it's strange - for the longest time it wasn't (I swear it wasn't, as I have been looking for solutions from the start of one particular project which required it).

Of recent it just started working. No rhyme, no reason. I don't know if there was a React update, a React Router update, or a Chrome update.

All I can say, is do a hard refresh and start from the top.

cjke avatar Feb 07 '18 22:02 cjke

scroll works for me.

happypeter avatar Apr 03 '18 11:04 happypeter

In my case content is fetched from API, so when the app loads, content is not there yet and the page remains at the top. Any ideas on how to get it working?

yantakus avatar May 14 '18 19:05 yantakus

@yantakus you can use this stackoverflow answer to scroll to a given element. Once your fetch is done, for example, you can then force a scroll to a given component (with window.scrollTo(0, this.ref.offsetTop)).

Yes, the solution is not linked to react-router-hash-link, but it's totally compatible. HashLinkwill scroll to a hash, and this technique will scroll on refresh after any async event.

yamsellem avatar Mar 28 '19 14:03 yamsellem

@rafrex, I face this issue as well:

If you go to https://7y6r6x2yr0.codesandbox.io/you#go-here from an external source or refresh/reload or enter it manually and press Enter, Chrome does not go to the <div id='go-here'> but stays at the top. Or did I miss anything?

The respective code sandbox: Edit 7y6r6x2yr0

/cc @cjke

desmap avatar Apr 11 '19 19:04 desmap

Same here.

zcmgyu avatar Sep 19 '19 04:09 zcmgyu

On a fresh page load the browser handles scrolling to the id that matches the hash in the url. The issue happens when there is a delay in the creation of the element with the id resulting in it not being on the page when the browser tries to scroll to it. Codesandbox has a fair amount of code that runs before loading the app resulting in the above failing example. Note that the example site, http://react-router-hash-link.rafrex.com/baz#section-three, doesn't suffer from this issue.

I have an idea of how to add initial page load scrolling to react-router-hash-link but want this react router issue to be fixed first.

In the mean time you can you can add initial load scrolling to your App's cdm

class App extends React.Component {
  componentDidMount() {
    if (window.location.hash) {
      const id = window.location.hash.replace("#", "");
      const element = document.getElementById(id);
      element.scrollIntoView();
    }
  }
...

You can see this working in codesandbox https://codesandbox.io/s/nifty-varahamihira-dj5qb

rafgraph avatar Sep 19 '19 18:09 rafgraph

Thank @rafrex I've made customHook for this one. In case of using lazy and Suspense, let's call useScrollToHash inside imported component.

import { useEffect } from 'react';

export default function useScrollToHash() {
  useEffect(() => {
    const { hash } = window.location;
    if (hash) {
      const id = hash.replace('#', '');
      const element = document.getElementById(id);
      if (element) element.scrollIntoView({ block: 'start', behavior: 'smooth' });
    }
  }, []);
}

zcmgyu avatar Sep 27 '19 00:09 zcmgyu

@zcmgyu thanks!

your custom Hook did help but i needed to did slight modification, any idea why? BTW. i have this problem only in Safari.

import { useEffect } from 'react'

export default function useScrollToHash() {
  useEffect(() => {
    //TODO: setTimeout with 0 made it work in Safari - i dont know why
    setTimeout(() => {
      const { hash } = window.location
      if (hash) {
        const id = hash.replace('#', '')
        const element = document.getElementById(id)
        if (element) {
          element.scrollIntoView({ block: 'start', behavior: 'instant' })
          window.scrollBy(0, -55)
        }
      }
    }, 0)
  }, [])
}

dejanstrancar avatar Dec 19 '19 17:12 dejanstrancar

In my case solution is wrap scrollIntoView in setTimeout with delay 100

if (element) {
    setTimeout(() => {
        element.scrollIntoView();
    }, 100);
}

Yaolegol avatar Nov 13 '20 15:11 Yaolegol

There is another trick that you can try, but it only works in cases where you exactly know the size of your async result beforehand. For example lets say you have a website with an async search result of 100 Lines (+ maybe a pagination). Then you could prefill the 100 lines synchronously with dummy lines/anchors (empty string), just so that the native scroll anchor mechanism works. Then as soon as your promise gets resolved the real data is filled in and you are already in the correct scroll position.

madnight avatar Dec 27 '20 17:12 madnight

Note This may be out of scope for this package.

Thanks for this package, I have been following this issue for quite a while.

The link works perfectly, however if a reload / refresh occurs, the page no longer scrolls down into position.

@cjke you may use this for reference. https://reactrouter.com/web/guides/scroll-restoration/scroll-to-top

imabp avatar Jan 22 '21 13:01 imabp

@zcmgyu thanks!

your custom Hook did help but i needed to did slight modification, any idea why? BTW. i have this problem only in Safari.

import { useEffect } from 'react'

export default function useScrollToHash() {
  useEffect(() => {
    //TODO: setTimeout with 0 made it work in Safari - i dont know why
    setTimeout(() => {
      const { hash } = window.location
      if (hash) {
        const id = hash.replace('#', '')
        const element = document.getElementById(id)
        if (element) {
          element.scrollIntoView({ block: 'start', behavior: 'instant' })
          window.scrollBy(0, -55)
        }
      }
    }, 0)
  }, [])
}

Yes this is exactly what I needed. Although I needed to remove the last window.scrollBy and it worked!

Edit: I guess all credit actually goes to @zcmgyu

Jackbaude avatar Jan 28 '21 15:01 Jackbaude

How is this implemented into a class component?

douglasrcjames avatar May 13 '21 01:05 douglasrcjames

@douglasrcjames see https://github.com/rafgraph/react-router-hash-link/issues/13#issuecomment-533251165

rafgraph avatar May 13 '21 01:05 rafgraph

@rafgraph thanks but I think I was trying to force fit this issue to fit my problem, I will ask another issue to answer my question

douglasrcjames avatar May 13 '21 01:05 douglasrcjames