-
Notifications
You must be signed in to change notification settings - Fork 960
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
State management in hash history #163
Comments
This is tricky - I like the idea of having cleaner URLs, but it seems tricky then to be able to generically support updating location state without causing a full re-render of the page. Among other things, without allowing that, I'm not aware of a good way to build support for browser-like scrolling that doesn't break horribly on e.g. Firefox - the sequencing of events on a POP transition means that you have to store the scroll position as you go, because you don't get a final "I'm about to leave the page" callback (and even then you'd still need to store the location somewhere, because the sequencing of the browser scroll restoration there does not give us what we want for free, the way we get it on Chrome). Maybe a better approach would be to implicitly use e.g. a hash of the current location as the state key when not using a query key, and make that the default, then warn when attempting to use state. It opens up a few edge cases, but I think it's a worthwhile trade-off. |
Agreed, this case becomes a lot more tricky. Assuming we actually have a way to do this (i.e. bring const history = createHashHistory({ alwaysEnableState: true }) I'm just trying to provide a better default for people who are using hash history but not using state. It's pretty low priority, because hash history is a hack anyway, but a lot of people still seem to be using it. And we still use it as the default in the router. |
If you're calling it a hack, how about we just use |
Oops, never mind, that doesn't work that way. |
I'd leave history.replace({...location, state: {...location.state, ...nextState}}) or whatever and get more control over what exactly is happening. Here's a somewhat complicated proposal that I think would mostly "just work":
Why (2) and (3)? (2) is to prevent users without query keys from explicitly using state with most normal patterns - it'd be horribly unsafe to use (3) is to let scroll behavior work - I don't want to fire listeners on persisting scroll position anyway, because that would lead to incredible re-rendering jank. Furthermore, for something like that, it's acceptable to bind the state to the path (in fact this is what the Gmail site does - if you navigate around, you'll see that scroll location for two history entries with the same path is tracked the same). This is a much less powerful API than per-entry |
Sounds like a good solution. The only troubling scenario I can think of is when using |
Note f12d632#commitcomment-16590812 – I don't think we can get away from having to generate a key from a hash of the URL if we want to maintain reasonable semantics around |
Can we keep location.key for |
This doesn't change it for I'm thinking about this in the context of scroll behavior – we need to always have access to some sort of key to be able to save down the scroll behavior in session storage. |
Let's keep this open to track the remaining issues with having a location key. |
Why not defer creating Many of us |
That's exactly what this issue is about, Don.
|
Yeah. I'm just frustrated by lack of movement on this when I see this change as not a mere enhancement but essential change. I would just use the full path+fragment as the location state key. So key for route |
I like @donpark's idea of just using the contents of the hash as the default This would be enough to deliver scroll behavior experience that matches e.g. the Gmail webapp for apps using hash history, which is good enough for me. |
As far as I'm concerned this issue is resolved in master. You can try it out right now in the 3.0 beta:
You don't need my permission to do this. In fact, I'd rather history give you const key = location.key || window.location.href This way you can at least opt in to potentially overwriting some previous state with your eyes wide open, because you chose they key. We already told you that the location doesn't have a unique key. @taion I'm not sure what you mean by "reasonable semantics around location.key". There are already reasonable, reliable semantics around location.key as it currently exists in master. We used to (in 2.x) say:
This means that when we don't actually have a key on the initial In 3.x we say:
At least now users will know if they have an authentic At this point I'm assuming this issue is still open because of confusion around how the semantics have changed. But as far as I'm concerned we can close. |
Fine. I'll just fork my way through the problem since we don't agree. |
@donpark Good luck! |
I still have open concerns here. Need to find some time to write them up. |
@donpark I think the current implementation on master actually does more or less what you want. However, it doesn't do what I want. For Why do we need something like So the requirement really is that these integrations like scroll behavior management need to be able to persist session storage in a way that's attached to the history entry. While technically all of this can be handled outside of history, it'd be a mess – basically it'd require making a separate independent wrapper around session storage, which is just really unnecessary. Thinking about this a bit more, maybe the best approach is to just bring back |
I am going to keep this issue open because the current semantics on 3.x are really not good for building reasonable extensible abstractions. It shouldn't be necessary to special-case hash history when building a wrapper for something like scroll behavior management. It doesn't make sense to do something like It's not a worthwhile tradeoff to make it significantly more difficult to build critically useful things like scroll management just to keep the code here a bit cleaner. Need to keep track of why we have things like |
Updating the issue title to be more generic. The remaining problems are the following:
|
First of all, please excuse a small rant: I'm soooooo tired of addressing the problems of hash history. Hash history is an old hack and is only required in IE <= 9 which Microsoft themselves don't even support anymore. Let's please keep that in mind when working on this library. I'm not saying we don't support hash history; we do. But at this point the vast majority of the discussions that happen on this repo have to do with hash history which really isn't that interesting. Let's move stuff forward and encourage our users to do the same. It's a difference of focus, that's all. I'm doing my best to focus on the future, not the past. Ok, enough ranting.
That sounds like a bug. I'll push a fix. We shouldn't give people a
This statement demonstrates a fundamental misunderstanding of what
Forget about building your scroll management thing, and the router, and everything else for just a minute, and imagine the following scenario:
In this scenario there are 2 entries in the history stack, and we're at the first one (index 0). Contrast that with the following:
In this scenario, there are 3 entries in the history stack, and we're at the 3rd one (index 2). The URLs in this scenario are identical to those in the first scenario, but the semantics are different. Now, if we calculate
In this scenario, a simple hash of the URL would be ok because
In this scenario the 3rd step actually takes us to a different location than the location in step 1, though the URLs are identical. This is why we can't generate a key from a hash of the URL. This is also why we can't reliably give you a key without putting it in the URL query string, because that's the only source of truth we have to go on when using hash history. Internally we use |
That's probably not the main use case of hash history at this point. Most users of hash history are probably using it to avoid having to configure a server – it's quite useful to not have to configure a server to set up many smaller web applications, especially ones that aren't meant as external-facing user applications. Moreover, as we've already discussed on #231 (comment), we are clearly not seeing eye-to-eye at this point as to the proper integration point between history and the router. If you're not especially interested in maintaining something that's a useful baseline abstraction for building a router and e.g. stripping out things like That's your call, but I'd rather this library be more useful rather than less useful. |
I chose to fork because @mjackson thinks this is a low-priority technical issue while it's a major UX issue to me. No amount of conversation can bridge the difference. |
That actually makes no sense. Just use a custom history and do |
with |
Yes, exactly. History v3 is not a drop-in replacement for v2 anyway so this discussion isn't going to affect anything in the near term for current router users. Just use the custom history path for now. Location state is often of somewhat limited use anyway, outside of things like scroll management. |
Yeah. Too bad one has to read source code to figure this stuff out. Ideal API for this stuff to me is to just set location hash as needed when I need to associate some state like when user scrolls. Having full control over URL is I think what most developers want. Anyway, thx for the help @talon. |
This is in the docs: https://github.com/reactjs/react-router/search?utf8=%E2%9C%93&q=queryKey |
Must have missed that. I found |
@donpark you haven't addressed my comments and you refuse to acknowledge @taion I'm done discussing on this thread. If you think the library has
|
@mjackson no I didn't bother looking at v3 beta because I was and still am too busy. your abrasive tone didn't help either. Be at peace knowing that I won't be wasting any more of your time. Good day to ya. |
It's not a matter of creativity or lack thereof. Trivially dependencies can accomplish whatever they want through some combination of hackery, code duplication, and calling into private APIs. The consideration in question is one of making it as easy as possible for libraries extending other libraries to do what their authors need to do. It's not a question of whether it's possible – it's a question of what semantics best allow people to do what they want to do. Abstraction for its own sake is not a good goal. My point here is that the lessons we've learned so far in building out scroll-behavior should inform how we choose to design interaction going forward; just as the lessons in building data integrations like async-props and react-router-relay shaped our development of the React Router API – and those lessons point against the |
You have time to come here and complain, but you don't have time to look at the fix? |
We should eliminate the query string when users aren't actually using state (i.e.
state
isnull
) with hash history. This would make ugly hash URLs slightly less ugly.The text was updated successfully, but these errors were encountered: