React-router: Redirects back to previous route call onLeave but not onEnter

Created on 22 Mar 2016  Â·  10Comments  Â·  Source: ReactTraining/react-router

Version

2.0.1

Test Case

http://jsbin.com/pitabavaba/1/edit?js,console,output

Steps to reproduce

  1. Console should display "loading data" since that happens on enter
  2. Click on "analytics", page header should change to "Fancy Analytics"
  3. Console should display "clearing unused data". This is GOOD
  4. Click on "dashboard", page header should change to "Fancy Dashboard"
  5. Console should display "loading data". This is GOOD
  6. Click on "Go home", page header will still display "Fancy Dashboard" since replace() was called
  7. Console should display "clearing unused data"

    Expected Behavior

onEnter should be called again since onLeave was called.

Actual Behavior

After replace() is called, going back to the dashboard results in no "loading data" message.


Calling onLeave implies that the page has been left. When replace is called, we should call onEnter to keep the flow consistent.

bug

Most helpful comment

Right, here's the simplest case:

<Route>
  <Route path="/foo" onEnter={onEnter} onLeave={onLeave} />
  <Redirect from="bar" to="/foo" />
</Route>

If the user navigates from /foo to /bar:

  1. We see a transition from /foo to /bar
  2. We call onLeave on /foo
  3. We call onEnter on /bar, which transitions us back to /foo
  4. The initial transition wasn't completed, so the current location state still corresponds to /foo
  5. We see a transition from /foo to /foo
  6. We don't call onEnter on /foo (nor onLeave on /bar)

The specific confusing behavior is that we call onLeave but not onEnter on /foo.

All 10 comments

@taion Is this not a bug?

No.

Oops, finger slipped – it's actually just how redirects work in React Router, I think, unless I'm misunderstanding something.

I see – okay, I'm going to update the issue to be more clear on what's happening.

@taion Thanks. I managed to work around the problem myself using an IndexRedirect. Redirect could have also been used if I was redirecting from something other than the index route.

I still think this is a bug though because it doesn't respect the onEnter/onLeave flow someone might expect.

Let me see if I can explain my reasoning a bit better.

Let's give routes two states: active and inactive. By calling onEnter and onLeave we enter either of those states. onEnter enters active and onLeave enters inactive.

  1. All routes start as inactive.
  2. We match route A, onEnter is called and route A is now in its active state.
  3. We click on a link and begin navigating to route B, onLeave is called for route A and route A is now in its inactive state
  4. As part of the previous step, the onEnter method of route B is called and it is now in its active state
  5. From route B, we navigate to route C. Since we are navigating away the onLeave method of route B is called and route B becomes inactive.
  6. This is where the bug happens: route C calls replace and we are sent back to route B. The onEnter method of route B isn't called and route B remains inactive even though it is now the active route.

While writing these a couple more of your comments came through. Hopefully this clears up anything that wasn't clear before.

Right, here's the simplest case:

<Route>
  <Route path="/foo" onEnter={onEnter} onLeave={onLeave} />
  <Redirect from="bar" to="/foo" />
</Route>

If the user navigates from /foo to /bar:

  1. We see a transition from /foo to /bar
  2. We call onLeave on /foo
  3. We call onEnter on /bar, which transitions us back to /foo
  4. The initial transition wasn't completed, so the current location state still corresponds to /foo
  5. We see a transition from /foo to /foo
  6. We don't call onEnter on /foo (nor onLeave on /bar)

The specific confusing behavior is that we call onLeave but not onEnter on /foo.

Related: https://github.com/reactjs/react-router/issues/3148

I believe the correct fix here might be to track some sort of pendingState in the transition manager, then calculate entering and leaving routes relative to the pending state. Not totally sure there – there are a few holes with that logic as well.

For example, suppose the target state has routes A, B, C, D, E. Suppose route B triggers a redirect in the onEnter. If this happens, we don't call onEnter on C, D, or E, so we probably shouldn't call onLeave on those either, but that would require yet additional bookkeeping.

We also can't just "rewind" the onLeave hooks, because they might trigger a redirect. Possibly we need to track some sort of "pending left routes", and e.g. intersect those in some appropriate way.

This seems messy enough that I don't see a good way to fix this in the near term. As always, we recommend not doing this sort of data fetching in onEnter hooks.

Hi,
I have the same issue, but it is related to the auth flow.

I have a login route and an index.
Index has onEnter set to a function that check if the user is logged in, otherwise it replace state with '/login'.

Login page has onEnter that redirect to '/' if the user is logged in yet.

Now, if I logged In and the go back with browser back button, it goes on login page and doesn't call onEnter, so I'm no more able to check authentication. The same if I logout and go back to index page.

Can we found some way to solve the issue?

Thanks!

You appear to be hitting something different, most likely a usage error on your part. Please consult one of the support forums.

Man you're right!!
It's my fault, but was a really similar bug that i have...

I have a middleware per hook system. It was bugged!

Sorry for mistakes!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ryansobol picture ryansobol  Â·  3Comments

davetgreen picture davetgreen  Â·  3Comments

misterwilliam picture misterwilliam  Â·  3Comments

alexyaseen picture alexyaseen  Â·  3Comments

maier-stefan picture maier-stefan  Â·  3Comments