Talha
Talha

Reputation: 817

Using react router, how can I pass component props using a route config?

I am trying to achieve the following using a single router config array. The thing to note here is that I have a state variable, storeName, which I am passing to the CategoryPage component.

import React, { useState } from 'react'
import { Switch, Route, BrowserRouter } from 'react-router-dom'
import { Navigation } from './Navigation'
import { HomePage } from './HomePage'
import { CategoryPage } from './CategoryPage'
import { ProductPage } from './ProductPage'
import { PageNotFoundPage } from './404Page'

export function App() {
    const [storeName, setStoreName] = useState('My Store')

    return (
        <div>
            <h1>{storeName}</h1>
            <BrowserRouter>
                <Switch>
                    <Route path="/category">
                        <CategoryPage storeName={storeName} />
                    </Route>
                    <Route path="/product">
                        <ProductPage />
                    </Route>
                    <Route path="/" exact>
                        <HomePage />
                    </Route>
                    <Route path="*">
                        <PageNotFoundPage />
                    </Route>
                </Switch>
            </BrowserRouter>
        </div>
    )
}

If I was to switch to using a route config object like so...

const routeConfig = [
    {
        path: '/',
        exact: true,
        component: HomePage,
    },
    {
        path: '/category',
        exact: false,
        component: CategoryPage,
    },
    // ...
]

// ...

<Switch>
    {routeConfig.map((route, i) => {
        return (
            <Route
                path={route.path}
                exact={route.exact}
                key={i}
            >
                <route.component />
            </Route>
        )
    })}
</Switch>

...what would be the most appropriate way to pass down props keeping in mind each component might need different props?

I suppose I could try to make the component key of the route config items a function which accepts every prop and then tries to map it to the component being returned. I'm not sure if this is the right way though.

Thanks!


Update #1

So I tried instead to return the component from the route config array like so:

const routeConfig = [
    {
        path: '/',
        exact: true,
        component: (props) => <HomePage {...props} />,
    },
    {
        path: '/category',
        exact: false,
        component: (props) => {
            return <CategoryPage {...props} />
        },
    },
]

// ...

const [storeName, setStoreName] = useState('My Store')

// ...

<Switch>
    {routeConfig.map((route, i) => {
        return (
            <Route
                path={route.path}
                exact={route.exact}
                key={i}
            >
                {route.component({ storeName })}
            </Route>
        )
    })}
</Switch>

This is working, but every component now would have every prop. Like in this case my HomePage component doesn't need the storeName prop but it still has it. Once I start adding other components which need other state variables, maybe this could cause a lot of variables to be stored in memory? It doesn't seem ideal.


Update #2

It's possible I'm going in the wrong direction by using route configs. Seems like that is actually opposite to react router's philosophy as I understand it from here https://reacttraining.com/react-router/web/guides/philosophy. Maybe I'll stick with my first implementation w/o the route config, but it'd still be nice to know how using the route config and passing in the correct props can be achievable.

Upvotes: 1

Views: 1146

Answers (1)

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196002

In your Update #1 just extract the props you want

const routeConfig = [
    {
        path: '/',
        exact: true,
        component: () => <HomePage />,
    },
    {
        path: '/category',
        exact: false,
        component: ({storeName}) => {
            return <CategoryPage storeName={storeName} />
        },
    },
]

Or you could use a list of relevant props for each component and extract them on the go

function pickProps(availableProps = {}, selection = []) {
  return selection.reduce(
    (props, selectedProperty) => {
      props[selectedProperty] = availableProps[selectedProperty];
      return props;
    },
    {}
  );
}

// ...

const routeConfig = [{
    path: '/',
    exact: true,
    component: HomePage,
  },
  {
    path: '/category',
    exact: false,
    component: CategoryPage,
    props: ['storeName'],
  },
  // ...
]

// ...
const componentProps = {storeName}
//....
<Switch>
    {routeConfig.map((route, i) => {
        return (
            <Route
                path={route.path}
                exact={route.exact}
                key={i}
            >
                <route.component
                   {...pickProps(componentProps, route.props)}
                />
            </Route>
        )
    })}
</Switch>

Upvotes: 2

Related Questions