react-router-hash-link
react-router-hash-link copied to clipboard
Doesn't scroll on reload / refresh
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.
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?
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 .
Sorry my bad, it is working!
Cheers
@cjke How did you get it to work? Having the same issue.
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.
scroll works for me.
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 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.
@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?
/cc @cjke
Same here.
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
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 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)
}, [])
}
In my case solution is wrap scrollIntoView in setTimeout with delay 100
if (element) {
setTimeout(() => {
element.scrollIntoView();
}, 100);
}
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.
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
@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
How is this implemented into a class component?
@douglasrcjames see https://github.com/rafgraph/react-router-hash-link/issues/13#issuecomment-533251165
@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