vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
603 stars 165 forks source link

Browser back navigation does not work when using replaceState with React enabled #19839

Open eberleant opened 2 weeks ago

eberleant commented 2 weeks ago

Description of the bug

If the current page used replaceState to modify the page history in an afterNavigation observer (for example, to add a query parameter), page history gets messed up. This causes back navigation using the browser back button to go back to 2 pages ago, instead of one page ago.

This worked in v23 but is broken in v24. A workaround is to disable React.

Expected behavior

Back navigation should only go back one page.

Minimal reproducible example

react-router-back-nav.zip

Run using mvn jetty:run and open localhost:8080.

Versions

tepi commented 2 weeks ago

The issue was assigned to a developer and is currently being investigated

tepi commented 2 weeks ago

Tested the given example. Looks like it is working as intended, since replaceState, as it's name suggests, replaces the URL in history without adding anything to the history. Changing replaceState to pushState in the example project produces expected results. Would this solution be ok for you?

The only difference between the two calls is that replaceState sends replace: true to react router, whereas pushState sends replace: false.

tepi commented 2 weeks ago

Here's a similar example from https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState. Looks like replaceState in vaadin-router has been working the wrong way all along.

Screenshot 2024-08-29 at 10 37 00
tepi commented 2 weeks ago

Never mind, I seem to have misunderstood the issue in the first place. Nevertheless, using pushState seems to produce the wanted behavior. I'll continue investigating for a fix.

eberleant commented 2 weeks ago

Hi, thanks for your work on this. In the past, we've tended to used replaceState in afterNavigation observers and pushState elsewhere. replaceState was used to prevent the user from getting stuck in a navigation loop where they weren't able to navigate backwards past the page with the afterNavigation observer (ie, the back button could never take them to the page before the afterNavigation observer, due to the page history getting continually added to).

From what I can see, there's been a change in behavior from Vaadin router to React router where pushState, when used within an afterNavigation observer, no longer causes this endless navigation loop.

If that's how it's meant to work, I'm OK with that! It will actually end up making some of our code a little bit cleaner 😄

tepi commented 2 weeks ago

Thanks for your reply! I see what you mean about navigation loop, it is very annoying. Anyway, looking further there seems to be an issue here, since the first navigate call should clearly add a history entry, and the replaceState call should replace the url for that entry, and that isn't happening now.

Did not dig deeper into react-router internals yet, but right now looks like if there are multiple navigate calls to it within the same server round-trip, it does not act on all of the calls. We've also had a couple of other similar issues with it. Will continue investigating.

tepi commented 1 week ago

This will most likely be fixed when a new version of react-router with this fix has been released.