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?
CodePudding user response:
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 thecategory
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>