Skip to content
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

Revert "Fix unnecessary remount when navigating back" #3513

Merged
merged 1 commit into from
Nov 17, 2024

Conversation

SteffenDE
Copy link
Collaborator

Reverts #3335
Fixes #3508.

The history API is the worst...

replaceRootHistory sets the initial type to "patch". Now assuming the following events:

  1. initial navigation to /page1

History:

==> /page1, type patch
  1. Navigating to /page2 (navigate, no patch)
    /page1, type patch
==> /page2, type redirect

Then we'd call replaceRootHistory after the new join:

    /page1, type patch
==> /page2, type patch

If we now use the back button, the browser would send us a popstate event including the previous state (type=patch). Instead of a navigate, we'd do a patch.

We could change replaceRootHistory to not assume type=patch, but then the initial PR would be useless as well, as there would still be a remount when navigating back.

To properly fix this, we'd need a way to get the state from before the popstate event to determine what navigation type was used, but that's not possible. Another option would be to always update the current state before pushing a new one to include a backType that would be used when navigating in the other direction. But this would require us to be able to distinguish a back from a forward navigation, as we'd only want to use the backType when navigating back. There are ways to do this (https://stackoverflow.com/questions/8980255/how-do-i-retrieve-if-the-popstate-event-comes-from-back-or-forward-actions-with), but it's definitely not pretty and doesn't seem worth it imho.

We might revisit this in the future, when the Navigation API is more widely available.

@SteffenDE SteffenDE merged commit 6e5f111 into main Nov 17, 2024
16 checks passed
@SteffenDE SteffenDE deleted the revert-3335-sd-initial-history branch November 17, 2024 18:55
SteffenDE added a commit that referenced this pull request Nov 30, 2024
Fixes #3536.

Browser history API strikes back (again). Because live navigation shares
the id of the view between live navigations, the following scenario could
happen:

1. User visits page 1 (initial nav)
2. User patches the page
3. User visits page 2 (live nav)
4. User patches the page
5. User uses browser back button (state from 3 -> live nav)
6. User uses browser back button (state from 2 -> PATCH)

In step 6, the user is still on page 2, but LiveView would try to patch
the page instead of performing a live navigation. This is only a problem
if the two pages use the same underlying LiveView module, otherwise the
patch request would fallback to a navigation.

This commit "fixes" this by modifying the current history entry at
step 2 to `redirect` before pushing the new state. This way, LiveView
does a live navigation when popping the state in step 6.

The underlying problem is that we cannot differentiate a forward from a
backward navigation when handling a popstate. If we could, we'd be able
to separately store the backwards and forwards navigation type. The
current approach will also do a live navigation when navigating forward
again, therefore if a user went back in history to step 1 and pressed
forward, we now do a live navigation instead of a patch, therefore
potentially losing state.

See also #3513 (comment).
SteffenDE added a commit that referenced this pull request Nov 30, 2024
Relates to #3513.

Browser history API strikes back (again). Because live navigation shares
the id of the view between live navigations, the following scenario could
happen:

1. User visits page 1 (state: initial)
2. User patches the page (state: patch)
3. User visits page 2 (state: redirect)
4. User patches the page (state: patch)
5. User uses browser back button (state from 3 -> live nav)
6. User uses browser back button (state from 2 -> PATCH)

In step 6, the user is still on page 2, but LiveView would try to patch
the page instead of performing a live navigation. This is only a problem
if the two pages use the same underlying LiveView module, otherwise the
patch request would fallback to a navigation. Also, we have an unnecessary
live navigation instead of a patch at step 5.

To fix this, we now differentiate if we are navigation backwards of
forwards and store the corresponding `backType` in the history state to
do the correct type of navigation on popState, which was already
mentioned as an idea in #3513.

=======================

1. User visits page 1 (initial nav)
state: initial

pre-push: update state to {type: "patch"}
2. User patches the page
post-push: push new state {type: "patch"}

pre-push: update state to {type: "patch", backType: "redirect"}
3. User visits page 2 (live nav)
post-push: new state {type: "redirect"}

pre-push: update state to {type: "redirect", backType: "patch"}
4. User patches the page
post-push: new state {type: "patch"}

5. User uses browser back button (popState backType "patch")
-> patch from the patched page back to non-patched page 2.

6. User uses browser back button (popState backType "redirect")
-> live nav from the page 2 to patched page 1

=======================

Finally, we can also prevent the unnecessary remount when navigating all
the way back properly (see #3335).
SteffenDE added a commit that referenced this pull request Nov 30, 2024
Relates to #3513.

Browser history API strikes back (again). Because live navigation shares
the id of the view between live navigations, the following scenario could
happen:

1. User visits page 1 (state: initial)
2. User patches the page (state: patch)
3. User visits page 2 (state: redirect)
4. User patches the page (state: patch)
5. User uses browser back button (state from 3 -> live nav)
6. User uses browser back button (state from 2 -> PATCH)

In step 6, the user is still on page 2, but LiveView would try to patch
the page instead of performing a live navigation. This is only a problem
if the two pages use the same underlying LiveView module, otherwise the
patch request would fallback to a navigation. Also, we have an unnecessary
live navigation instead of a patch at step 5.

To fix this, we now differentiate if we are navigation backwards of
forwards and store the corresponding `backType` in the history state to
do the correct type of navigation on popState, which was already
mentioned as an idea in #3513.

=======================

1. User visits page 1 (initial nav)
state: initial

pre-push: update state to {type: "patch"}
2. User patches the page
post-push: push new state {type: "patch"}

pre-push: update state to {type: "patch", backType: "redirect"}
3. User visits page 2 (live nav)
post-push: new state {type: "redirect"}

pre-push: update state to {type: "redirect", backType: "patch"}
4. User patches the page
post-push: new state {type: "patch"}

5. User uses browser back button (popState backType "patch")
-> patch from the patched page back to non-patched page 2.

6. User uses browser back button (popState backType "redirect")
-> live nav from the page 2 to patched page 1

=======================

Finally, we can also prevent the unnecessary remount when navigating all
the way back properly (see #3335).
SteffenDE added a commit that referenced this pull request Nov 30, 2024
Fixes #3536.
Relates to #3513.

Browser history API strikes back (again). Because live navigation shares
the id of the view between live navigations, the following scenario could
happen:

1. User visits page 1 (state: initial)
2. User patches the page (state: patch)
3. User visits page 2 (state: redirect)
4. User patches the page (state: patch)
5. User uses browser back button (state from 3 -> live nav)
6. User uses browser back button (state from 2 -> PATCH)

In step 6, the user is still on page 2, but LiveView would try to patch
the page instead of performing a live navigation. This is only a problem
if the two pages use the same underlying LiveView module, otherwise the
patch request would fallback to a navigation. Also, we have an unnecessary
live navigation instead of a patch at step 5.

To fix this, we now differentiate if we are navigation backwards of
forwards and store the corresponding `backType` in the history state to
do the correct type of navigation on popState, which was already
mentioned as an idea in #3513.

=======================

1. User visits page 1 (initial nav)
state: initial

pre-push: update state to {type: "patch"}
2. User patches the page
post-push: push new state {type: "patch"}

pre-push: update state to {type: "patch", backType: "redirect"}
3. User visits page 2 (live nav)
post-push: new state {type: "redirect"}

pre-push: update state to {type: "redirect", backType: "patch"}
4. User patches the page
post-push: new state {type: "patch"}

5. User uses browser back button (popState backType "patch")
-> patch from the patched page back to non-patched page 2.

6. User uses browser back button (popState backType "redirect")
-> live nav from the page 2 to patched page 1

=======================

Finally, we can also prevent the unnecessary remount when navigating all
the way back properly (see #3335).
SteffenDE added a commit that referenced this pull request Nov 30, 2024
Fixes #3536.
Relates to #3513.

Browser history API strikes back (again). Because live navigation shares
the id of the view between live navigations, the following scenario could
happen:

1. User visits page 1 (state: initial)
2. User patches the page (state: patch)
3. User visits page 2 (state: redirect)
4. User patches the page (state: patch)
5. User uses browser back button (state from 3 -> live nav)
6. User uses browser back button (state from 2 -> PATCH)

In step 6, the user is still on page 2, but LiveView would try to patch
the page instead of performing a live navigation. This is only a problem
if the two pages use the same underlying LiveView module, otherwise the
patch request would fallback to a navigation. Also, we have an unnecessary
live navigation instead of a patch at step 5.

To fix this, we now differentiate if we are navigation backwards of
forwards and store the corresponding `backType` in the history state to
do the correct type of navigation on popState, which was already
mentioned as an idea in #3513.

=======================

1. User visits page 1 (initial nav)
state: initial

pre-push: update state to {type: "patch"}
2. User patches the page
post-push: push new state {type: "patch"}

pre-push: update state to {type: "patch", backType: "redirect"}
3. User visits page 2 (live nav)
post-push: new state {type: "redirect"}

pre-push: update state to {type: "redirect", backType: "patch"}
4. User patches the page
post-push: new state {type: "patch"}

5. User uses browser back button (popState backType "patch")
-> patch from the patched page back to non-patched page 2.

6. User uses browser back button (popState backType "redirect")
-> live nav from the page 2 to patched page 1

=======================

Finally, we can also prevent the unnecessary remount when navigating all
the way back properly (see #3335).
chrismccord pushed a commit that referenced this pull request Dec 2, 2024
Fixes #3536.
Relates to #3513.

Browser history API strikes back (again). Because live navigation shares
the id of the view between live navigations, the following scenario could
happen:

1. User visits page 1 (state: initial)
2. User patches the page (state: patch)
3. User visits page 2 (state: redirect)
4. User patches the page (state: patch)
5. User uses browser back button (state from 3 -> live nav)
6. User uses browser back button (state from 2 -> PATCH)

In step 6, the user is still on page 2, but LiveView would try to patch
the page instead of performing a live navigation. This is only a problem
if the two pages use the same underlying LiveView module, otherwise the
patch request would fallback to a navigation. Also, we have an unnecessary
live navigation instead of a patch at step 5.

To fix this, we now differentiate if we are navigation backwards of
forwards and store the corresponding `backType` in the history state to
do the correct type of navigation on popState, which was already
mentioned as an idea in #3513.

=======================

1. User visits page 1 (initial nav)
state: initial

pre-push: update state to {type: "patch"}
2. User patches the page
post-push: push new state {type: "patch"}

pre-push: update state to {type: "patch", backType: "redirect"}
3. User visits page 2 (live nav)
post-push: new state {type: "redirect"}

pre-push: update state to {type: "redirect", backType: "patch"}
4. User patches the page
post-push: new state {type: "patch"}

5. User uses browser back button (popState backType "patch")
-> patch from the patched page back to non-patched page 2.

6. User uses browser back button (popState backType "redirect")
-> live nav from the page 2 to patched page 1

=======================

Finally, we can also prevent the unnecessary remount when navigating all
the way back properly (see #3335).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Browser Back Button Fails to Update Content After Navigation in Phoenix LiveView
1 participant