React-router: Add support for redirect/to property in routes definition for react-router-config

Created on 18 May 2017  路  6Comments  路  Source: ReactTraining/react-router

Currently, if you want to use react-router-config and have a route redirect to another route, you need to do something like the following:

import { Redirect } from 'react-router';

import AppComponent from './AppComponent';
import PathAComponent from './PathAComponent';
import PathBComponent from './PathBComponent';

const routes = [
  {
    component: AppComponent,
    routes: [
      {
        path: '/',
        exact: true,
        component: () => <Redirect to="/pathA"/>
      },
      {
        path: '/pathA',
        exact: true,
        component: PathAComponent
      },
      {
        path: '/pathB',
        exact: true,
        component: PathBComponent
      }
    ]
  }
]

This works fine, but it would be nice to have a simplified shorthand for this case, perhaps something that looks like the following:

const routes = [
  {
    component: AppComponent,
    routes: [
      {
        path: '/',
        exact: true,
        redirect: '/pathA'
      },
      {
        path: '/pathA',
        exact: true,
        component: PathAComponent
      },
      {
        path: '/pathB',
        exact: true,
        component: PathBComponent
      }
    ]
  }
]

This should be fairly easy to support by modifying the implementation of the renderRoutes function to look for a redirect property on routes in addition/instead of the component property.

feature stale

Most helpful comment

@gl0gl0 Good question about redirecting with params.

I think it should be as simple as something like this:

{ path: '/:id', exact: true, component: (props) => <Redirect to={"/pathA/" + props.match.params.id } /> }

Give that a try and let me know if it works.

All 6 comments

I'm not sure if this is your use case as well, but right now I'm trying to implement a redirect after successful login.

E.g., The user navigates to a protected resource, is redirected to the login page, logs in, and then gets redirected back to the original destination.

The way I'm currently doing this is by wrapping the protected resource in a higher order component:

const restricted = (BaseComponent) => {
  class Restricted extends Component {
    componentWillMount() {
      this.checkAuthentication(this.props);
    }
    checkAuthentication(params) {
      const { history, dispatch, } = params
      if(!checkCredentials(dispatch)) { // Checks localStorage for existing token; return true or false
        history.replace({ 
          pathname: '/login', 
          redirect: params.location.pathname,
        })
      }
    }
    render() {
      return <BaseComponent {...this.props} />
    }
  }
  return withRouter(connect()(Restricted))
}

Which works fine for me since I can read the redirect property in the login logic (using a Saga in this case):

function* loginFlow (action) {
  try {
    const { payload } = action
    // Perform login logic...

    // Get the redirect pathname using selector to find state.router.location.redirect...
    const pathname = yield select(getRedirectPathname)
    // Redirect to original destination and clear redirect destination from router state
    yield put(push({
      pathname: pathname ? pathname : '/', 
      redirect: undefined,
    }))
    return token
...

This works well, however a problem arises if there are any additional route changes before the redirect happens. E.g., Let's say the user gets sent to the login page, but then goes to the signup page if they don't have an account.

Even if I keep the same redirect logic in the signup Saga, the fact that there was a route change clears out the redirect flag from state.router.location.

A good solution would be to find a way to keep a location.redirect entry on every frame of the history stack; the router reducer would just copy it to the next state if it was defined.

I'm new to this whole redux thing so I'm not sure how to accomplish that, but I'll dig around the code a little bit and see what I can find.

I have a feeling that this change would need to go through the history repo, but I'm not yet sure.

Following @jharris4 example, on how it is possible to add redirects in the config file at the moment, like:

{ path: '/', exact: true, component: () => <Redirect to="/pathA"/> }

What happens if the path you want to redirect has a param, and you wish the redirect to take that param as well? For example:

{ path: '/:id', exact: true, component: () => <Redirect to="/pathA/:id"/> }

Is there way to do that?

@gl0gl0 Good question about redirecting with params.

I think it should be as simple as something like this:

{ path: '/:id', exact: true, component: (props) => <Redirect to={"/pathA/" + props.match.params.id } /> }

Give that a try and let me know if it works.

@jharris4 it works! Thank you!!

Minor bug that I ran into while trying to implement this: even though you're using a redirect, you still have to provide exact: true if the route you're redirecting from matches multiple routes (e.g. for the common case of a home page / redirecting to something like /dashboad).

If you don't provide the exact param, it still redirects, but seems to get caught up on the previous match so that a "new" match isn't applied. (And any calls to renderRoutes seem to not execute again.) Hopefully this helps anyone else running into the same thing.

Also: this issue is about a year-and-a-half old now--are there any feature implementations for it yet? Any official word that no one's planning to implement it.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Waquo picture Waquo  路  3Comments

jzimmek picture jzimmek  路  3Comments

imWildCat picture imWildCat  路  3Comments

maier-stefan picture maier-stefan  路  3Comments

Radivarig picture Radivarig  路  3Comments