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

Traversal direction from current state (outside events) #267

Open
GriffinSauce opened this issue Aug 16, 2023 · 2 comments
Open

Traversal direction from current state (outside events) #267

GriffinSauce opened this issue Aug 16, 2023 · 2 comments

Comments

@GriffinSauce
Copy link

Hi, so first off: this API rocks.

I'm looking into implementing transition animations for my app, which is powered by React Router.

For a "slide over" animation I'd need to know the direction of traversal. Now this is pretty easy to determine in the event handlers by comparing indexes but because my routing is handled by another library it would be very helpful to be able to access this information statically as well. (to avoid race conditions between the event handling)

So we have:

  • currentEntry provides information about the current state
  • entries() provides information about the entire stack
  • ... what's missing is the user behaviour, how they have traversed the stack, I could have 3 entries but actually a path of 10 back-and-forth actions. That is my actual navigation history.

I'm not sure if this steps too far outside of the scope of the API but I'd love to hear your opinions on this.

In terms of a solution, getting something like lastEntry would solve the problem, but perhaps a list of last visited entries (probably limited to reasonable number) could support more use cases.

@tbondwilkinson
Copy link
Contributor

I think you can implement this pretty simply with a currententrychange listener.

const steps = [];
navigation.addEventListener('currententrychange', (e) => {
  if (e.navigationType === 'traversal') {
    steps.add({from: e.from, to: navigation.currentEntry});
  }
});

That would give you a list of {to, from} objects that represent every history change your application has observed.

@GriffinSauce
Copy link
Author

Thanks @tbondwilkinson !
I was doing something similar, with the event handler you don't really need the steps, just the last one:

let lastNavigationEvent
window.navigation.addEventListener('currententrychange', event => {
  lastNavigationEvent = event
})

export const getLastNavigationDirection = (): 'unknown' | 'back' | 'forward' => {
  if (
    !lastNavigationEvent || // First landing
    lastNavigationEvent.navigationType === 'reload' ||
    lastNavigationEvent.navigationType === 'replace'
  ) {
    return 'unknown'
  }

  const lastIndex = lastNavigationEvent.from.index
  const currentIndex = navigation.currentEntry.index
  if (currentIndex === lastIndex) return 'unknown'
  if (currentIndex > lastIndex) return 'forward'
  if (currentIndex < lastIndex) return 'back'
}

(might have some rough edges, just exploring the ideas)

But the main thing I'm worried about is a race-condition between that event handler and the react-router event handler that triggers re-rendering and animations and I have no control over the latter (aside from maybe monkey-patching it).

So, the green path:

  • user triggers navigation
  • step is recorded
  • getLastNavigationDirection returns correct direction

And the bug:

  • user triggers navigation
  • app handler triggers, getLastNavigationDirection returns incorrect direction
  • step is recorded .. too late

I guess this can be mitigated by making sure the order of attaching listeners is correct but that feels quite fragile to me. Should I be less worried about that?

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

No branches or pull requests

2 participants