Reputation: 804
I'm stuck with dynamic nested routes. Please help to solve this problem.
I'm making a pet-project e-commerce store with showcase and admin panel where admin can add/edit/remove products, categories, brands. Everyting related to admin panel should start with a route domain.com/admin/
and all other routes (without /admin/) should be related to showcase.
My layout for showcase is:
My routes:
const routes = useRoutes([
{
path: PATHS.showcase,
element: <ShowcasePage />,
children: [
{
path: '/',
element: <DiscountProductsPage />,
},
{
path: ':url',
children: [
{
index: true,
element: <CategoryPage />,
},
{
path: ':id',
element: <ProductsPage />,
},
],
},
{ path: PATHS.wishlist, element: <WishlistPage /> },
],
},
{
path: PATHS.admin,
element: <AdminPage />,
children: [
{ path: PATHS.products, element: <ProductsPage /> },
{
path: PATHS.settings,
element: <SettingsPage />,
},
],
},
]);
Path object:
export const PATHS = {
showcase: '/',
settings: 'settings',
products: 'products',
admin: '/admin/',
wishlist: '/wishlist'
}
On page load I fetch categories which is an array like this:
const categories = [
{
id: '-N8A28QULvmu36EqRZDW',
description: '',
name: 'Hoodies',
url: 'hoodies',
},
{
id: '-z34A29MMMvmu36EqRZXX',
description: '',
name: 'Jeans',
url: 'jeans',
},
];
Then based on this array I create a menu list passing category as Link state:
<nav>
<ul>
{categories.map((category) => (
<li key={category.id}>
<Link to={category.url} state={category} onClick={closeMenu}>
{category.name}
</Link>
</li>
))}
</ul>
</nav>
In category page I use state={category}
for rendering data like this.
const CategoryPage: React.FC = () => {
const location = useLocation();
const { id, name } = location.state as Category;
const { products } = useSelector((state: RootState) => state.product);
const categoryProducts = products.filter((product) => product.category.id === id);
return (
<section>
<h1>{name}</h1>
<ProductCardList products={categoryProducts} />
</section>
);
};
Now I want to add a one more dynamic nested route. If user clicks on a product card in category page, then he should land on this url:
domain.com/:categoryUrl/:productId
domain.com/jeans/-s1B99QULvmu36EqCCPP
I added children :id
to CategoryPage routes and with that I get an error in CategoryPage component:
Uncaught TypeError: Cannot destructure property 'id' of 'location.state' as it is null.
I understand what causes the error. I don't understand how to fix that. Might be my approach for rendering CategoryPage is wrong? And I need to fix that first and then everything will work?
To clarify what I want:
I want a base e-commerce layout with categories menu in header and a product list.
If user clicks on category in menu then he should land on category page with products for that category
If user clicks on a product in category page then he should land on product page with URL like this: domain.com/jeans/-s1B99QULvmu36EqCCPP
children: [
{
path: ':id',
element: <ProductPage />,
},
I added children route above for category page route because product page is a child of a category page
Upvotes: 1
Views: 2250
Reputation: 202686
You are rendering CategoryPage
as a layout route but it isn't rendering an Outlet
component for nested routes to match and render their content into. Since you describe wanting to render these routes/components all separately anyway then the Outlet
isn't want you want.
Refactor your route config to render CategoryPage
on an index route so CategoryPage
and ProductPage
are not a parent-child route relationship, per se. "/:url"
will render an Outlet
component by default and CategoryPage
will be rendered as the index route when the path is exactly "/:url"
, and ProductPage
will render when the path is "/:url/:id"
.
const routes = useRoutes([
{
path: PATHS.showcase,
element: <ShowcasePage />,
children: [
{
path: '/',
element: <DiscountProductsPage />,
},
{
path: ':url',
children: [
{
index: true,
element: <CategoryPage />,
},
{
path: ':id',
element: <ProductPage />,
},
],
},
{ path: PATHS.wishlist, element: <WishlistPage /> },
],
},
]);
Upvotes: 1