-
Notifications
You must be signed in to change notification settings - Fork 26
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
Should appHistory.push() and update() fire the navigate event? #42
Comments
It depends on what you mean. They definitely navigate the document in the sense of how the spec and implementation sees it. (They're same-document navigations, like a fragment navigation.) So I don't think it's possible to call them harmful in that way, since it's something history.pushState already does. Could you expand on this a bit more? The intention is for appHistory.push() to navigate the document in the same way history.pushState() does, i.e. be a same-document navigation that updates the URL/state but does not update the |
Hmm. I don't think |
We discussed this a bit offline. Whether or not pushState is a navigation aside, the main concern is about the In particular, today the model people use is: do stuff to update the page, and then use Whereas, the mental model of a pure app history API user is: perform a navigation, either with @dvoytenko's is concerned about mixed codebases, e.g. ones migrating from the current model to the app history model. How does their One solution here, which I think is pretty good, is to be more explicit about the navigation initiator. E.g., inside the appHistory.addEventListener("navigate", e => {
// Don't intercept cross-origin navigations; let the browser handle those normally.
if (!e.sameOrigin) {
return;
}
// Don't intercept fragment navigations.
if (e.hashChange) {
return;
}
// **** Don't handle history.pushState/replaceState() navigations from older parts of the app ****
// Those parts of the app will do their own UI updating.
if (e.initiator === "history-pushstate" || e.initiator === "history-replacestate") {
return;
}
if (e.formData) {
e.respondWith(processFormDataAndUpdateUI(e.formData));
} else {
e.respondWith(doSinglePageAppNav(e.destination));
}
}); |
The navigate event initiator does indeed help with my concern. I'm still not sure where or not a It's my hope that the vast majority of applications can completely stop using history APIs and instead just rely on the Another option is to also add a boolean flag to |
The idea of steering applications away from using history APIs entirely is also worth considering. E.g., we wouldn't have location.navigate(url, { state, replace, navigateInfo }); |
I'd really like to move in that direction. I'd only keep |
So in that direction I think the relevant questions are:
For (1), I'm pretty sold they should fire the navigate event, with some initiator property to let you filter them out as necessary. Giving people a holistic view of all navigations (in the browser sense, i.e. things which change the URL/state/etc.) seems important for a variety of use cases. For (2) and (3), I like the idea of converting |
Agreed on 1 - if they don't fire the I'm not sure I agree on changing Perhaps I'm not fully understanding the added value of changing it to be off on its own, when everything else is still part of |
Yeah, I'm not sure I explained it that well... Another way to think of it is just deleting Recall that the bigger issue being discussed here is the two models in #42 (comment). Removing |
Ah, so the added value is essentially: it has a better chance to force people to rethink how their code flows with Though it doesn't guarantee it (I could see devs writing articles that still just say "change Hopefully I'm understanding you correctly - forgive me for my slowness in understanding. 🙂 |
No worries, I'm happy to walk through it more.
The difference is in my point (2). In particular, So just changing |
Ah, thank you for your patience in explaining it to me; I think I understand now. So a SPA router would just need to add a navigate handler that would essentially be appHistory.addEventListener('navigate', (event) => {
if(event.sameOrigin) {
reRenderSPA();
event.preventDefault();
}
) (maybe the router could add an additional check in But I do now see the value of having a single api that can fire both cross-document and also SPA navigations. It seems like it would even allow the developer to not worry about the environment that they're in; they could call That is, if I've finally understood you correctly 🙂 |
Yeah, that's exactly it! To be clear, I'm not 100% sure we should go this route, but it makes a good deal of sense... |
(Not extending |
+1 to yes
I think I'm starting to feel like a full cross-document navigation for push/update makes sense. It's always been pretty bizarre that history.pushState() does NOT fallback to requesting the URL from the server. And to the current behavior as history.pushState it's trivial to install a navigation handler that just preventsDefault on anything that comes from appHistory that shares the same URL path, etc.
I think if you're updating any part of the URL, it would be a cross-document navigation. If you update the hash or do not update the URL (just state) it would NOT perform a corss-document navigation because the "resource" is assumed to be the same. Maybe? I believe this is how Location works today re:URL changes.
I feel pretty strongly that we shouldn't add this to |
I feel like we're converging on push and update, nice. Regarding where to add it, I don't have strong opinions. I think @dvoytenko's perspective is something like " |
I would vote for everything being added to On a somewhat related note: I think I may have missed this in the discussion about the But it's also possible I missed that in our conversation above 😊 |
Closes #36 by moving from appHistoryEntry.state to getState() and setState() methods. This adds the ability to modify the state of non-current entries as a bonus. Solves much of #42 by making push() and update() navigate by default, although it does not yet include the initiator idea. As part of this we simplify update() significantly, since now if you want to change state without performing a navigation, you would use setState(). This makes the URL argument required for it. For symmetry, I removed url from the options for push().
Closes #36 by moving from appHistoryEntry.state to getState() and setState() methods. This adds the ability to modify the state of non-current entries as a bonus. Solves much of #42 by making push() and update() navigate by default, although it does not yet include the initiator idea. As part of this we simplify update() significantly, since now if you want to change state without performing a navigation, you would use setState(). This makes the URL argument required for it. For symmetry, I removed url from the options for push().
Closes #36 by moving from appHistoryEntry.state to getState() and setState() methods. This adds the ability to modify the state of non-current entries, as well as a statechange event, as a bonus. Solves much of #42 by making push() and update() navigate by default, although it does not yet include the initiator idea. As part of this we simplify update() significantly, since now if you want to change state without performing a navigation, you would use setState(). This makes the URL argument required for it. For symmetry, I removed url from the options for push().
I think we're pretty solid on this for now, with #115 tracking the remaining issue. |
The older
history.pushState
and counterpart did not navigate the document. This is used extensively by routers to reconcile navigations with the history structure when a state might need to be added or updated to provide for back behavior and other application features. There are already several ways to navigate, includinglocation = '...'
,location.assign()
,link.click()
, etc. Perhaps the navigation in this API is unnecessary and might be even harmful.The text was updated successfully, but these errors were encountered: