React-router: Combine the behavior of DefaultRoute and Redirect

Created on 26 Feb 2015  路  12Comments  路  Source: ReactTraining/react-router

I'd like to have a routing component that, like DefaultRoute, matches when no other child route matches _and_ that, like Redirect, transitions to a new child path. An example using the make believe DefaultRouteRedirect illustrates:

<Route name="application" path=":application">
  <DefaultRouteRedirect to="versions" />
  <Route name="versions" path="versions" handler={ Versions } />
</Route>

I've tried a couple different approaches to get this behavior, e.g., <Redirect from="*" />, <Redirect from="" /> but nothing seems to work quite right. Am I missing something, or does react-router not currently support this?

_EDIT_ @taurose points out that my description is incorrect. I do want the behavior of DefaultRoute w/r/t to matching on the parent route and the behavior of Redirect w/r/t to transitioning to a child route regardless of what I wrote.

The context for this routing pattern is that the child routes are a set of tabs and I need to pick one as the default, but also make it explicit in the URI which one is picked. The reason to make it explicit is that the route handlers use the current URI to make decisions about which data to fetch.

Most helpful comment

For others arriving here via Google, IndexRedirect is what you want.

For example, instead of

 <Redirect from="*" to="characters" />

which doesn't work as you'd expect (as noted above in this thread), use

 <IndexRedirect to="characters" />

All 12 comments

like DefaultRoute, matches when no other child route matches

That's not what DefaultRoute is. You're describing NotFoundRoute. DefaultRoute matches if the parent's path matches exactly (.. and no other child route matches).

Try

<Route name="application" path=":application">
  <Route name="versions" path="versions" handler={ Versions } />
  <Redirect from="*" to="versions" />
</Route>

The order is important, redirect must be the last route since react-router matches top to bottom (depth-first). This should make it behave similar to NotFoundRoute (match last and match everything). from="*" is optional, since that's the default if neither path nor from is set.

You're right, my description was incorrect, but I do want the behavior of DefaultRoute, ie, match when the parent route matches exactly. IOW, I want a component to automatically redirect from parent. I don't believe <Redirect from="*" /> does this regardless of where it is placed among the child routes.

@BenjaminMalley Right now, you could do:

<Route name="application" path=":application">
  <Route handler={ RedirectToVersions } />
  <Route name="versions" path="versions" handler={ Versions } />
</Route>

Your RedirectToVersions handler component would look like this:

var RedirectToVersions = React.createClass({
  statics: {
    willTransitionTo: function (transition) {
      transition.redirect('versions');
    }
  }
  render: function () {}
});

Granted it's a little verbose, but this is the first time I've ever seen this use case. Perhaps, instead of defaulting to *, <Redirect> should use its parent path by default?

That would probably break some existing use cases...

@mjackson That looks reasonable for now. The verbosity wouldn't be an issue if I didn't have to specify the path name to transition to with the RedirectToVersions component.

Should the first nested Route component be DefaultRoute? It looks like it.

In general, I _am_ doing a bunch of stuff that I think is pretty non-standard for react-router. I use the RouteHandler mixin so I can dynamically fetch data for a component at the route that it matches (ie, _not_ the current route, but the level of the current route that it wakes up at), which is the source of this problem and other things I've been struggling to implement. I've found that, unless I do this, it's difficult to re-use components and routing structures at multiple levels of the hierarchy, which we do extensively. Otherwise, I would have to write a route handler wrapper for each component that fetches data. Probably this is a bad idea, but it would be convenient for my purposes if route handlers could be informed of the route they wake up at, instead of just being able to see the current route & all child routes.

@BenjaminMalley You could always just

<Route name="application" path=":application">
  <Route handler={ RedirectTo('versions') } />
  <Route name="versions" path="versions" handler={ Versions } />
</Route>

and then

function RedirectTo(destination) {
  return React.createClass({
    statics: {
      willTransitionTo: function (transition) {
        transition.redirect(destination);
      }
    }
    render: function () {}
  });
}

But ya, we should probably make this easier.

But ya, we should probably make this easier.

How about adding path to DefaultRoute?

<Route name="app">
  <DefaultRoute path="tab1" />
  <Route path="tab2" />
  <Route path="tab3" />
</Route>

Makes sense, doesn't it?

@taurose Wow, that actually does make sense now that I think about it. We would need to slightly modify the matching behavior, but I think that would work :D

:+1: That looks great! The problem with the willTransitionTo static method is that the current route params are unavailable, so it fails when it tries to redirect.

the current route params are unavailable

@BenjaminMalley It's the second argument to willTransitionTo. The full method signature is

willTransitionTo: function (transition, params, query, callback)

I will merge ON THE SPOT a <DefaultRedirect/> pull request as long as its got a test and docs.

Closing this issue to show just how serious I am.

did this ever happen? seems like allowing a path on DefaultRoute would be a really logical solution..

For others arriving here via Google, IndexRedirect is what you want.

For example, instead of

 <Redirect from="*" to="characters" />

which doesn't work as you'd expect (as noted above in this thread), use

 <IndexRedirect to="characters" />
Was this page helpful?
0 / 5 - 0 ratings

Related issues

winkler1 picture winkler1  路  3Comments

nicolashery picture nicolashery  路  3Comments

ArthurRougier picture ArthurRougier  路  3Comments

andrewpillar picture andrewpillar  路  3Comments

Radivarig picture Radivarig  路  3Comments