Reputation: 817
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
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