Josh Liu
Josh Liu

Reputation: 526

React Router Dom V6 pass array to path

I want to render same page by multiple routes in react-router-dom v6 like how it was in v5. However, I couldn't find a efficient way to do it.

Example in v5 I can do this:

    <BrowserRouter>
      <Switch>
        <Route path={["/dashboard", "/home"]} render={<Home />} />
        <Route path="/other" render={<OtherPage/>} />
        <Route path={["/", "/404"]} render={<NotFound />} />
      </Switch>
    </BrowserRouter>

But in v6, it is said that the path needs to be a string.

The only way I found that can achieve this is to separate them as follow:

    <BrowserRouter>
      <Routes>
        <Route path="/dashboard" element={<Home />} />
        <Route path="/home" element={<Home />} />
      </Routes>
    </BrowserRouter>

Which means I have to write <Home /> multiple times.

I want to keep my code as CLEAN as possible.

I checked the official documentation, but didn't mention about this part. And I did research, but couldn't find a solution.

Upvotes: 14

Views: 15515

Answers (7)

pgarciacamou
pgarciacamou

Reputation: 1732

There is no need for custom solutions. The cleanest solution is to loop internally:

<Routes>
  {["/dashboard", "/home"].map(path => (
    <Route 
      key="Home" // optional: avoid full re-renders on route changes
      path={path}
      element={<Home />}
    />
  ))}
</Routes>

For your use case with only two routes, I personally think having separate routes is more readable. But for my use case; where I have 6+ routes pointing to the same component, it doesn't make sense any longer.

Key prop

The fixed key is a "hack" that's only needed for specific cases where your users have a way to switch between the URLs internally and/or if the component is heavy. Using the same key for all routes in the Array tells React that the component didn't unmount when React Router switches routes and that only the props changed, this way React doesn't re-render the entire branch. It works because React Router v6 never renders two routes at any point in time.

Playground

https://stackblitz.com/edit/github-otdpok?file=src/App.tsx

Upvotes: 14

Awais Niaz
Awais Niaz

Reputation: 49

{["/exstv", "/exstv/:id"]?.map((item) => {
    return <Route path={item} element={<SportsTv />}></Route>
 })}

Upvotes: 0

Haroon Hayat
Haroon Hayat

Reputation: 455

I have a similar problem creating a project: The simple solution is to map over all paths:

Here is the Solution:

<BrowserRouter>
      <Switch>
        <Route path={["/videos", "/images","/news"]} render={<Result />} />
      </Switch>
    </BrowserRouter>

Now we have to convert this code into react-router-dom v6:

<BrowserRouter>
      <Routes>
        {['/images','/videos','/news'].map(path => (
          <Route key={path} path={path} element={<Result />}
))}
      </Routes>
</BrowserRouter>

Upvotes: 1

arsi
arsi

Reputation: 51

For me this worked for react-router-dom v6

<Routes>
    <Route path='/' element={<Navigate to="/search" />} />
    <Route exact path='/videos' element={<Results />} />
    <Route exact path='/news' element={<Results />} />
    <Route exact path='/images' element={<Results />} />
    <Route exact path='/search' element={<Results />} />
</Routes>

Upvotes: 0

A_A
A_A

Reputation: 340

I created this helper function and it works in React Router v6:

const renderMultiRoutes = ({ element: Element, paths, ...rest }: MultiRoutes) =>
  paths.map((path) => <Route key={path} path={path} {...rest} element={Element} />);

Then I can do the following:

<Routes>
  {renderMultiRoutes({
    paths: ['/', '/dashboard'],
    element: <Feature />,
  })}
</Routes>

Upvotes: 9

Kirpich643
Kirpich643

Reputation: 121

I was in a similar situation. I have some different routes that should render same page layout. In v5 it was implemented as:

<Switch>
    <Route
      exact
      path={[
        ROOT_ROUT,
        SIGN_UP_ROUT,
        FORGOT_PASSWORD_ROUT,
        CHANGE_FORGOT_PASSWORD_ROUT,
      ]}
    >
      <AuthPageTemplate>
        <Switch>
          <Route exact path="/" component={SignIn} />
          <Route exact path="/sign-up" component={SignUp} />
          <Route exact path="/forgot-password" component={ForgotPassword} />
          <Route
            exact
            path="/change-forgot-password/:code"
            component={ChangeForgotPassword}
          />
        </Switch>
      </AuthPageTemplate>
    </Route>
    <Route component={Page404} />
  </Switch>

And after update this code solves the same task:

<Routes>
  <Route
    path="/"
    element={
      <AuthPageTemplate>
        <Outlet />
      </AuthPageTemplate>
    }
  >
    <Route index element={<SignIn />} />
    <Route path="/sign-up" element={<SignUp />} />
    <Route path="/forgot-password" element={<ForgotPassword />} />
    <Route
      path="/change-forgot-password/:code"
      element={<ChangeForgotPassword />}
    />
  </Route>
  <Route path="*" element={<Page404 />} />
</Routes>

It works fine for me.

Upvotes: 0

Josh Liu
Josh Liu

Reputation: 526

As a result I downgraded to v5. However, here is a solution based on @MikeAbeln's point map. I built a wrapper component to do the trick.

import { Route } from 'react-router-dom';

export default function MultiRoute({ element: Element, path: paths, ...rest }) {
    return (
        <>
            {Array.isArray(paths) ? paths.map((path) =>
                <Route path={path} {...rest} element={props => <Element {...props} />} />
            ) :
                <Route path={paths} {...rest} element={props => <Element {...props} />} />
            }
        </>
    );
}

Then I can do as follow to make my Routes.js file CLEAN enough and easy scale:

    <BrowserRouter>
      <Routes>
        <MultiRoute path={["/dashboard", "/home"]} element={<Home />} />
        <MultiRoute path="/other" element={<OtherPage/>} />
        <MultiRoute path={["/", "/404"]} element={<NotFound />} />
      </Routes>
    </BrowserRouter>

UPDATE

This will return an Error "Error: [MultiRoute] is not a component. All component children of must be a or <React.Fragment>" as @Drew Reese mentioned. Needs to be fixed.

Kindly comment below or leave an answer and thanks in advance.

Upvotes: 2

Related Questions