-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Totally confused on scroll behaviours #690
Comments
This is what should happen by default. Can you repro this? |
You can set a breakpoint here and see whether you hit it: Any change of something like bad Chrome plugins overriding |
It's a little difficult to share the source as it's an internal prototype for my work. I think I know what the problem is... It seems that because I have my structure like this:
The router is setup so the Looking deeper in the code, it makes sense as the default behavior is to Does that seem right? But also, this sort of layout doesn't seem too unusual for a web app? I don't want the scroll bars of the For me then, I'd need to override the scroll behavior when I first create the router? Or is there some other tricks React Router has that would help with this? I have tried this:
But it doesn't work 100% all the time. It doesn't always go to the top when the URLs change. Would really appreciate any help on this. |
Right, that makes sense..
I see. We actually had a similar layout at one point in our webapp. I'm glad we don't use it anymore because we had all sorts of issues with this (e.g. you can't click Safari top bar on iPhone to scroll to top—precisely because A way around this would be to give If you still want to do like you said, yes, you should probably specify custom First, remove any updateScrollPosition: function (position, actionType) {
function scrollTo(x, y) {
var contentEl = document.getElementById('content');
if (contentEl) {
contentEl.scrollLeft = x;
contentEl.scrollTop = y;
} else {
window.scrollTo(x, y);
}
}
switch (actionType) {
case LocationActions.PUSH:
case LocationActions.REPLACE:
scrollTo(0, 0);
break;
case LocationActions.POP:
if (position) {
scrollTo(position.x, position.y);
} else {
scrollTo(0, 0);
}
break;
}
} (I took code from default Does this help? This is similar to what you wrote but I just want to make sure before trying to diagnose further. If it doesn't work, can you please write specific steps to reproduce the problem? |
Wow, thank you. That's great, you went above and beyond with that reply. It's great that you've setup React Router in such a way to allow easy customisation and thank you for the examples from Medium and Twitter. This was pretty much my last bit to crack when it came to React Router and I can see now that there isn't really a generic way this could be handled as it would depend on the particular layout. Is it insane that another attribute could be introduced called something like "scrollToTop" that you could pass to a particular route which could do the same thing as your code? Meaning I wouldn't have to "hard code" the content id into a custom scroll behaviour? I totally understand that it's mostly a better idea to avoid layouts with Thanks again. Great reply. |
The problem is we can't know which particular div is scrollable (and whether your layout is intended to be scrollable via a vertical div or document body). Even if we find a div with Since we can't do that for generic case, we solve this by allowing you to plug completely custom behavior with BTW, just to clarify, the code I gave you is based on |
Hey. So I made the layout changes you advised. There is no funky inner scroll, the main content is just on the body now. So I've changed my code to be this:
Because the default behaviour didn't seem to work. But I'm still having this problem. When I'm loading content (so the So I have a route like this I'm stumped :( |
Let's start with this. Edit: it would help if you could share your code (or parts of it) so I could run them. |
Hey there. The default scroll behavior does just what I described in my message. And with my custom one above it does the same. Maybe I'm just not understanding what the browser is doing? The window does scroll to the top, but after half a second or so, goes back down the page. I was trying to find a pattern... It's possibly trying to return to a point on the page it remembers per URL? ...if I return to the same URL, it tries to go back to that particular scroll point? Or is it to do with the sub components loading (as their states are being loaded from an API). I'm doing nothing else when it comes to scrolling anywhere else in the app. Maybe I'm just not understanding what the browser is trying to do. I'm coming from a Backbone world, so maybe I'm having a hard time working it out. I can't really share this particular code base as it's for a prototype for work. |
Does this happen after clicking a link, or browser back/forward? Which browser? |
On browser click. The best example is one I explained. It has a |
Obvious question but have you already tried several browsers? |
This seems to be the problem because you can reproduce it even with a custom scroll behavior. AFAIK router only sets the scroll position in scroll behavior, so if the problem persists, it likely isn't with the router. Since you can't share the code, if I were you, I'd try:
Finally, are you using |
Interesting, even trying it in Safari... It doesn't do it. Seems to only be Chrome. (can't test easily in Firefox, I have -webkit- prefixes all over the place) Note as well, this only happens when I'm returning back to the same route (or with the same ) so a Definitely no jQuery plugins or |
You should use Autoprefixer :-)
Can you try |
Totally on the Autoprefixer, but it's just a prototype and so only needs Chrome really ;) Hmm, HistoryLocation doesn't seem to do too much. A pattern seems to be emerging though. It's like it's remembering where the scroll position was on a certain route. So if I'm on |
Lol I think I know what this is, but this sounds I like I made the stupidest mistake possible when writing this. :-P Can you verify whether this change fixes your issue? |
Or maybe it's not enough.. I think we're recording every push and store positions by route, but this will bite us as soon as you go A -> B -> A without ever going back. We should probably keep a stack instead. |
Hey there, no didn't do anything there. Have I hit an edge case? But it seems like a legit thing that an app might do, right? Thanks so much for your patience with this. |
Thanks for sticking with us. I was just thinking aloud. Do I understand correctly that this is your issue?
|
So... with the default scroll behavior (nothing custom or funny) My app has a range of routes. Going to any of these by following So it's more like following these Hope that makes sense! |
Oh well. This may be a Webkit issue I bumped into, but it's not really related to the router. Is there any chance that at the moment you're transitioning to the next track, inertial (rubber-band) scrolling is overflowing? (not overflowing:) (overflowing:) You can check by waiting for rubber band effect to finish before clicking on the link to next track. |
Definitely nothing to do with the rubber band effect. I know what you mean there, but even if I wait for a long time before clicking on another link, it has this weird behavior :( |
Do you ever click on a track you've been on before? Is this
kind of situation? If this is the case, can you reproduce the problem without going to a route you've been on before? |
Yes, the pattern seems to be when I go to a route I've been before, it's like it's attempting to return me back to where that route was before. That's fine for a back button action, but not when you're trying to click a link and it simply be at the top. It's confusing that it scrolls back down. For the back button though, that sort of behavior would make sense. |
Makes sense. This is how router currently works, but I agree it needs fixing. Thank you for helping me understand the issue! |
@gaearon Would you mind explaining how this happens? As far as I can tell, the router itself never scrolls to a recorded position for actions other than POP. And even that would happen only with ImitateBrowserBehavior, which he tried to replace. |
@taurose is right, I must have been high when I wrote this. Default scrolling behavior does not use stored position when handling There is no other place in router that calls
Unfortunately, I can't really help with first possibility without a reproducible example. Here's a sample app (source) that uses I'm closing this for now, but feel free to reopen if you have ideas about how we can reproduce this. |
One thing you could check is put an If it is not being called for the transitions where scroll positions gets messed up, make sure that:
Please feel free to reopen if you find that custom scroll behavior's method is not being called when it should! |
Thank you for all your help. I still can't work out what is going on. I have made my own function which takes me back up to the top if the id of the route has changed. I'm happy enough with this for the moment, can't work out what else to do. |
I guess the easiest way is to take everything out of your components until you find what is causing the issue. |
I had this problem when I was moving from the save route, but changing the query parameters. It would go to the top any time I changed something else, but query parameters it seemed to think weren't different. |
That's how it's expected to work, unless I misunderstood your comment. Query parameters don't change scroll position. |
How do GET parameters not mean a new page? Is there an option to configure it to scroll to the top? I use GET parameters for pagination, and I expect when a user clicks another page that it will scroll to the top as the entire contents of the page changes. |
As I wrote above, you can either promote page number to be in componentWillReceiveProps(nextProps) {
// assuming you pass query in props from parent route handlers
if (this.props.query.page !== nextProps.query.page) {
window.scrollTo(0, 0);
}
}
Not all query parameters are the same. Consider a search page. You wouldn't want page to scroll every time you type a letter, but search terms likely go into the query. Similar for "filter" options on page with filters and sorting. So you can't say "scroll to top" is desirable for every use case with query parameters. And as I wrote above you have easy ways out. |
Forgive me, my browser did not find any other results for componentWillReceiveProps on this page. However, it seems like a bad user experience to have every letter they type show up in their browser history. They'll but hitting the back button forever! My situation is actually a search engine! Every time they do a new search, the entire page loads with new data, just like any other normal history-adding event. So they need to see all that lovely new data! If I scroll to the top every time this changes though, the users will be very upset when they hit the back button and the page isn't where it was when they went forward! This is the great thing about react-router, because it keeps track of those things, so I don't have to. |
You can use |
Hey there.
I can tell by looking through the issues that scrolling and React Router seems have a lot of confusion around it. I honestly have gone through the issues and even done searches through the source code to work this out.
I have my routes set up like this:
Take the
ProfilePage
for example, this ajax loads data for lots of sub components on it's page. Sometimes they can make the page very long vertically. Those sub components can also link to otherProfilePage
routes and so on a profile it could have a URL like/#/profile/123
and on that it could also link to another profile page like/#/profile/999
. If I click a sub component of a profile page that is down the list, I want it to just load the new profile page and have it scroll back to the top, so it feels like a whole new page has loaded. At the moment it seems to preserve the scroll position (as best it can) which is mostly down the list or around where I clicked the link for the other profile, which is very annoying. I don't want it to do that, I just want it to go back up to the top like it's loaded a brand new profile.I've tried everything to try and make this work. I seem to see a lot about adding
ignoreScrollBehavior
on the routes. I've done this, but it doesn't fix the problem. I'm really, really stumped. Can someone help please? It would be really appreciated!Great work so far on this project by the way, it's been very useful. Just this problem is the thing that I'm stumped with.
The text was updated successfully, but these errors were encountered: