React : how to redirect a match of a list of components to sub-path (/templates => /templates/list)

Viewed 647

I have a React app, and I do not want to replicate the functionality in all my components to redirect the user to /<component>/list if they go to /<component> - how would I do this at a higher level?

I have a layout component that would be the place to do it if I were to guess. I have a getRoutes method in there that processes a routes definitions file. However, what I would like to do, is provide a list of components that must redirect to that /<component>/list path if they go to one of the components in that list:

List: ['/templates', '/activities', '/trials']
Visiting:
    /templates: redirects to `/templates/list`
    /activities: redirects to `/activities/list`
    /custom: does nothing, renders CustomComponent
    /trials: redirects to `/trials/list`
    /trials/new: does nothing, renders new method

Is this possible? I tried using , but was unsuccessful at capturing items without the path being explicitly defined:

<Switch>
    <Route path="/templates">
        {<Redirect to="/templates/list"/>}
    </Route>
    ...
</Switch>

Is there a way to do it something like this? :

var paths = ['templates', 'trials'];
getRoutes = routes => {
   return (
      [if path matches /{paths[0..n]]
          <Redirect to={{pathname: /paths[0..n]/list}} />
      [/if]
   );
}

I don't think I am on the right track here, but is there something similar to what I am trying to accomplish?

2 Answers

Sure, you can embed logic into JSX with {}

const list = ['templates', 'activities', 'trials']

return (
  <Switch>
  {list.map(item => (
      <Route 
        path={"/"+item}
        render={() => <Redirect to={"/"item+"/list"}/>}
      />
   )}
 </Switch>
)

You'll have to put in a handler for the ones with different logic (like custom), so you could restructure the list to use objects instead like:

[{path: 'subpath1', component: null}, {path: 'subpath2', component: component2}]

and then access the properties accordingly in the map:

{
    list.map(item => {
      if (item.component) {
        return (<Route path={"/"+item.path} component={item.component}/>)
      } else {
        return (
          <Route 
            path={"/"+item.path}
            render={() => <Redirect to={"/"item.path+"/list"}/>}
          </Route>
        )
      }
   }) 
}

Yes, you can use the following syntax :paramname(path1|path2) which will match path1 and path2 and name the parameter as paramname. Then in render you can redirect based on that parameter to wherever you want

    <Route
      path="/:toplevel(templates|activities|trials)"
      exact
      render={({ match }) => (
        <Redirect to={`/${match.params.toplevel}/list`} />
      )}
    />

All this is mentioned at the path docs of the react-router-dom

Any valid URL path or array of paths that path-to-regexp@^1.7.0 understands.

And in that package's docs see the custom-match-parameters section

Related