Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to make a Not Found page with complex dymanic nested routes in React Router 6?

How to make a Not Found page with complex dynamic nested routes in React Router 6?

For example I have dynamic routes for categories and product pages. It looks like this:

site.com/jeans
site.com/jeans/qazXzx123122

To render the data on category and product pages I use the same approach:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  • Get URL from useParams
  • Find category and products with the same URL in Redux-state
  • Render data on a page

CategoryPage

const { products } = useSelector((state: RootState) => state.product);
const { categories } = useSelector((state: RootState) => state.category);
const { url } = useParams();
const categoryProducts = products.filter((product) => product.category.url === url);
const category = categories.find((category) => category.url === url) as Category;

If I go to wrong URL e.g. to site.com/jeans111 then app crashes because there’s no category with that URL and category === undefined. I tried to solved the problem with useEffect hook and redirect but no success.

Not working approach

useEffect(() => {
  if (!category.name) {
    return navigate('/', {
      replace: true,
    });
  }
}, [category, navigate]);

Routes

const routes = useRoutes([
  {
    path: PATHS.showcase,
    element: <ShowcasePage />,
    children: [
      {
        path: '/',
        element: isDataLoaded ? <DiscountProductsPage /> : <Loader />,
      },
      {
        path: ':url',
        children: [
          {
            index: true,
            element: isDataLoaded ? <CategoryPage /> : <Loader />,
          },
          {
            path: ':id',
            element: isDataLoaded ? <ProductPage /> : <Loader />,
          },
          {
            path: '*',
            element: <NotFound />
          }
        ],
      },
      { path: PATHS.wishlist, element: isDataLoaded ? <WishlistPage /> : <Loader /> },
      {
        path: PATHS.cart,
        element: isDataLoaded ? <CartPage /> : <Loader />,
      },
      {
        path: `${PATHS.cart}/${PATHS.success}`,
        element: <CheckoutSuccessPage />,
      },
    ],
  },
  {
    path: PATHS.admin,
    element: <AdminPage />,
    children: [
      {
        path: PATHS.orders,
        element: <OrdersPage />,
      },
      {
        path: PATHS.products,
        element: <ProductsPage />,
      },
      {
        path: PATHS.settings,
        element: <SettingsPage />,
      },
    ],
  },
]);

>Solution :

I think your approach is correct, but you want to redirect off the route when there is no category to render content for.

Example:

const navigate = useNavigate();
const { url } = useParams();
...
const category = categories.find((category) => category.url === url) as Category;

useEffect(() => {
  if (!category) {
    navigate('/', { replace: true });
  }
}, [category, navigate]);

Though it may be better to display a fallback screen instead of just bouncing the user off the route.

const navigate = useNavigate();
const { url } = useParams();
...
const category = categories.find((category) => category.url === url) as Category;

...

return category
  ? (
    ...JSX...
  )
  : (
    <div>No match found.</div>
  );
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading