Reputation: 119
I am using react router v6 to define routes like this.
<Routes>
<Route path="*" element={<Navigate to="/" />} />
<Route path="/" element={<HomePage />} />
<Route path="/shop">
<Route index element={<ShopPage />} />
<Route path=":category" element={<CategoryPage />} />
</Route>
</Routes>
Here's the ShopPage code to navigate to "/shop/:category"
const categories = ['shoes', 'jeans', 'sweaters']; // originally populated using an api
{categories.map(category => <Link to=`/shop/${category}`>${category}</Link>}
I want to restrict navigating to CategoryPage only when the category param has a value from the above defined set. What I'm doing currently is conditionally rendering stuff on CategoryPage depending on category param received.
For example, if user navigates to "/shop/xyz", I just show a 'not found' error & a link to go back to shop. What I would like though is to somehow pre-check destination path and to not move to CategoryPage at all in this case.
I tried to do something like
<Route path=":category('shoes'|'jeans'|'sweaters')" element={<CategoryPage />} />
as mentioned in this post but that just redirects me to root path '/' for all param values.
Is there a way to do this?
Upvotes: 4
Views: 1824
Reputation: 203408
Regular expressions were removed from route paths in react-router-dom@6
. See "What Happened to Regexp Routes Paths?" for details.
You've a couple options:
Explicitly render the routes you want to match. For this you map the categories in the same way as you did the links.
<Routes>
<Route path="*" element={<Navigate to="/" />} />
<Route path="/" element={<HomePage />} />
<Route path="/shop">
<Route index element={<ShopPage />} />
{categories.map(category => (
<Route
key={category}
path={category} // <-- "/shop/shoes", "/shop/jeans", "/shop/sweaters"
element={<CategoryPage />}
/>
))}
</Route>
</Routes>
Validate the category
route path parameter in a matched component. I'd suggest creating a category wrapper component that reads and validates the category
path parameter and bounces a user off the route if the category isn't valid.
import { Navigate, useParams } from 'react-router-dom';
const CategoryWrapper = ({ categories = [], children }) => {
const { category } = useParams();
const isValid = !categories.length || categories.includes(category);
return isValid ? children : <Navigate to="/" replace />;
};
<Routes>
<Route path="*" element={<Navigate to="/" />} />
<Route path="/" element={<HomePage />} />
<Route path="/shop">
<Route index element={<ShopPage />} />
<Route
path=":category"
element={(
<CategoryWrapper categories={categories}>
<CategoryPage />
<CategoryWrapper>
)}
/>
</Route>
</Routes>
Upvotes: 4