React Router V6: A Practical Guide with Shoe Store Application

React Router V6: A Practical Guide with Shoe Store Application

How to make application fast with React Router?

Routing is a technique for navigating a user to a different web application page based on user actions and requests. React router is a popular library that enables the routing to a react application. It is used to create and navigate different URLs of the application. React router performs client-side routing in react application. It increases performance and enhances the speed of web applications.

React router comes with three packages:

  • react-router the core package of the react-router.

  • react-router-dom DOM version of react-router, which means router for the web components.

  • react-router-native router component for mobile app development.

React Router has recently released version 6, which is packed with a plethora of amazing features. This version boasts a range of improvements, from smaller bundle sizes to object-based routes, giving users an even more efficient and intuitive way to navigate their applications. In this guide, we'll take a look into react-router-dom developing a shoe store application. We'll use static data for this application.

Prerequisites:

  • You'll need a development environment running node.js.

  • React JS

  • Chakra UI for styling

Installation:

We are creating a shoe store web application with react so first we need to set up react project and create a new react project by npx-create-app. We are creating a web-based application so we need to install react-router-dom it by npm install --save react-router-dom.

We are using Chakra components to build user interfaces of the application so we need to install Chakra UI also. To install Chakra UI execute the following command:

npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion

This command will install chakra UI, emotion, and framer motion that will be used by Chakra.

At this point, we have set up our react application and installed react-router in it. execute npm start to start the application. The application will start on a browser window and the screen will look like this:

We have completed our first step and started the react application.

Create data.js inside a src folder and copy the following code, these data we'll use throughout the application.

export const shoesData = [
  {
    name: "Valour Blue",
    img: "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/1_903cd85a-aee1-48a4-be1a-2c67a15af928.jpg?v=1671191499",
    category: "women",
    price: 4999,
    SKU: "M-PR-MAR-0017:NVY/NVY:40/6",
    description:
      "Hit the gym in these comfy and durable Men's Mesh Training Shoes! They have been made with good quality Flyknit material which keeps them light and ensures durability. These shoes feature lace detailing, a round toe shape, and a padded insole. The EVA/TPR outsole provides grip and comfort.",
    product_images: [
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/1_903cd85a-aee1-48a4-be1a-2c67a15af928.jpg?v=1671191499",
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/2_1336522a-107d-41d2-9180-d9d787a4f89b.jpg?v=1671191499",
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/3_18f2970b-102f-4175-a760-4f51a3522b81.jpg?v=1671191499",
    ],
  },
  {
    name: "Jordan Mars 270 London",
    img: "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/1_bd07a863-a0cf-4684-abe6-79035ea9f4d8.jpg?v=1666352087",
    category: "men",
    price: 2999,
    SKU: "M-PR-MAR-9828:NVY/NVY:40/6",
    description:
          "Hit the gym in these comfy and durable Men's Mesh Training Shoes! They have been made with good quality Flyknit material which keeps them light and ensures durability. These shoes feature lace detailing, a round toe shape, and a padded insole. The EVA/TPR outsole provides grip and comfort.",
        product_images: [
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/2_772ad7c2-d37e-413f-a41c-3b62ccb2ec98.jpg?v=1666352087",
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/3_77dea9d9-1847-4129-8ad7-ff193989f186.jpg?v=1666352087",
    ],
  },
  {
    name: "Men's Mesh Training Shoes",
    img: "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/M-PR-VEL-0015-BLU-YEL.jpg?v=1666334487",
    category: "men",
    description:
          "Hit the gym in these comfy and durable Men's Mesh Training Shoes! They have been made with good quality Flyknit material which keeps them light and ensures durability. These shoes feature lace detailing, a round toe shape, and a padded insole. The EVA/TPR outsole provides grip and comfort.",
    price: 5999,
    SKU: "M-PR-MAR-9828:NVY/NVY:40/6",
    product_images: [
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/3_756b2f1e-dcc7-4850-8422-a1a81381b72a.jpg?v=1666334487",
      "https://cdn.shopify.com/s/files/1/0371/5416/0772/products/2_7d540f5b-05a1-4667-b891-4a61431c3a26.jpg?v=1666334487",
    ],
  },
];

Wrap Application to the Providers

We need to wrap our application with the react-router and chakra-UI provider to use all the features of these components.

Open App.js

import { RouterProvider } from "react-router-dom";
import { router } from "./router";
import { ChakraProvider } from "@chakra-ui/react";

function App() {
  return (
    <ChakraProvider>
      <RouterProvider router={router} />
    </ChakraProvider>
  );
}

export default App;

import ChakraProvider from @chakra-ui/react and RouterProvider from react-router-dom and Wrap RouterProvider with ChakraProvider. Pass your routers that we'll create below in RouterProvider through props. Now, we can use every component of Chakra UI and access the routing features provided by react-router in our application.

Creating Routes:

Now, we have to define our routes for the application. For this shoe store application, we have the following pages:

  • Home Page

  • Product Page

  • Product Details Page

Let's define our route for these pages. Create an routes.js inside src folder. You can create a file routes.js by the execution of the following command:

touch src/routes.js

After creating a file, define routes for the application by using the object-based approach. In React router V6, we have two options to define our routes. The first one is the JSX or component-based approach to define the routes and the second and the latest are the object-based approaches. I have used the second one for this application.

import { createBrowserRouter } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
import Layout from "./components/Layout";
import ProductPage from "./components/ProductPage";
import ProductDetailsPage from "./components/ProductDetailsPage";

export const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout />,
    children: [
      {
        index: true,
        path: "/",
        element: <Home />,
      },
      {
        path: "/:category",
        element: <ProductPage />,
      },
      {
        path: "/products/:category/:product_name",
        element: <ProductDetailsPage />,
      },
    ],
  },
]);

We have to import createBrowserRouter API from the react-router-dom to initialize the router for the shoe application. It uses the DOM History API to update and manage the URLs.

createBrowserRouter takes an array of objects and each object defines an individual route.

  • path it defines the route URL.

  • element It defines what should be rendered on the UI when the user redirects to this path.

  • index This would be true/false, this will be rendered when the user has not clicked on any route. This route will be rendered.

Creating a Layout Component:

The layout component is a parent component that will render a child component. For this application, I have just created a navbar in this layout that will be rendered on all the pages. So, this should a parent component of all the pages:

Let's create a navbar first that will be rendered on layout component:

touch component/Navbar.js

Add the following code in Navbar.js

import { Box, Container, Text, HStack,Heading, Image, Input } from "@chakra-ui/react";
import { NavLink } from "react-router-dom";

const menuLinks = [
  {
    name: "home",
    link: "/",
    label: "Home",
  },
  {
    name: "men",
    link: "men",
    label: "Men",
  },
  {
    name: "women",
    link: "women",
    label: "Women",
  },
  {
    name: "kid",
    link: "kids",
    label: "Kids",
  },
];

const NewsBar = () => {
  return (
    <Box bg={"#DA3E52"} p={"6px"}>
      <Text textAlign={"center"} color={"white"}>
        Free Delivery on all Orders above Rs. 2000. You may Contact us at:
        012-029717991
      </Text>
    </Box>
  );
};

const Navbar = () => {
  return (
    <Container maxW={"100%"} p={0}>
      <NewsBar />
      <Box p={"16px"}>
        <HStack justifyContent={"space-between"}>
          <HStack spacing={"10px"}>
            {menuLinks.map((link) => {
              return (
                <NavLink to={link.link} style={{ textDecoration: "none" }}>
                  <Text textDecoration={"none"} fontSize={"18px"} color="black">
                    {link.label}
                  </Text>
                </NavLink>
              );
            })}
          </HStack>
          <Heading>Shoe Store</Heading>
          <Box>
            <Input placeholder="Search" size="lg" p={"6"} fontSize={"20px"} />
          </Box>
        </HStack>
      </Box>
    </Container>
  );
};

export default Navbar;

We have created 4 links here, the home page, and Men, Women, and Kids that will show all the collections of these categories.

Now, Create a Layout.js file inside an src folder by following the command:

touch components/Layout.js

Then, import the Navbar component from Navbar.js and Outlet from react-router-dom

import { Outlet } from "react-router-dom";
import Navbar from "./Navbar";

const Layout = () => {
  return (
    <div>
      <Navbar />
      <Outlet />
    </div>
  );
};

export default Layout;

Outlet: It will be used to render the child components inside a parent component. This allows nested UI to show up when child routes are rendered. So, all the pages like home, shoe details, and categories pages will be rendered under this parent component.

UI will look like this, you might get an error because we have not created our Home, Product Page and Product Details page yet.

Creating a Product Card Component:

Create ProductCard.js file inside a component folder and paste the following code:

import {
  Card,
  CardHeader,
  CardBody,
  CardFooter,
  Button,
  Divider,
  Text,
  ButtonGroup,
  Image,
  Stack,
  Heading,
} from "@chakra-ui/react";
import { Link } from "react-router-dom";

export const ProductCard = ({ image, name, category }) => {
  return (
    <Link to={`/products/${category}/${name}`}>
      <Card maxW="sm">
        <CardBody>
          <Image
            src={image}
            borderRadius="lg"
            width={"100%"}
            height={"300px"}
          />
          <Stack mt="2" spacing="3">
            <Heading size="md">{name}</Heading>
            <Text color="red.600" fontSize="2xl">
              $450
            </Text>
          </Stack>
        </CardBody>
        <Divider />
        <CardFooter>
          <ButtonGroup spacing="2">
            <Button variant="solid" colorScheme="red">
              Buy now
            </Button>
          </ButtonGroup>
        </CardFooter>
      </Card>
    </Link>
  );
};

Link: The link component will render a clickable link through which the user can navigate to other pages of the application. Provide the route of the other page in to props of the Link component.

Here, the card is wrapped with a Link component. When users click on the card they will navigate to the product details page.

Creating a Home Page:

Create Home.js inside component folder and paste the following code:

import { Container, Heading, SimpleGrid } from "@chakra-ui/react";
import { ProductCard } from "./ProductCard";
import { shoesData } from "../data";

const Home = () => {
  return (
    <Container maxW={"100%"} p={"16px"}>
      <Heading>All Shoes</Heading>
      <SimpleGrid columns={4} spacing={10}>
        {shoesData.map((shoeDetail) => {
          return (
            <ProductCard
              image={shoeDetail.img}
              name={shoeDetail.name}
              category={shoeDetail.category}
            />
          );
        })}
      </SimpleGrid>
    </Container>
  );
};

export default Home;

The home page will just render all the products available in data.js with the ProductCard component that we already created earlier.

The home page will look like this:

Creating Product Category Page:

Create ProductPage.js inside a component folder with touch command, and paste the following code:

import { Container, Heading, SimpleGrid } from "@chakra-ui/react";
import { ProductCard } from "./ProductCard";
import { shoesData } from "../data";
import { useParams } from "react-router-dom";

const ProductPage = () => {
  const { category } = useParams();

  const handleFilterShoes = () => {
    return shoesData.filter((shoeDetail) => shoeDetail.category === category);
  };

  return (
    <Container maxW={"100%"} p={"16px"}>
      <Heading>{category.toUpperCase()} - All Shoes</Heading>
      {/* If no data found */}
      {!handleFilterShoes().length && (
        <Heading textAlign={"center"}>No Product Available!</Heading>
      )}
      <SimpleGrid columns={4} spacing={10}>
        {handleFilterShoes().map((shoeDetail) => (
          <ProductCard
            image={shoeDetail.img}
            name={shoeDetail.name}
            category={shoeDetail.category}
          />
        ))}
      </SimpleGrid>
    </Container>
  );
};

export default ProductPage;

This page will show the collection of shoes on the basis of the category, it will take the category from the route URL.

useParams: The useParams Hook is a React Router Hook that allows you to access dynamic parameters from the current URL. It returns an object of key/value pairs of URL parameters, which can be used to access the match params of the current <Route>. This allows you to display data that is specific to each route and is dependent on the dynamic parameters in the current URL.

The data will be filtered out on the basis of category and the filtered data will be shown in the form of a grid.

Creating Product Details Page:

The last page we need to create is the product details page, create ProductDetailsPage.js inside a component folder.

import {
  Container,
  Box,
  SimpleGrid,
  Image,
  Text,
  Heading,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { shoesData } from "../data";

const ProductDetailsPage = () => {
  const { product_name } = useParams();
  const [shoeDetails, setShoeDetails] = useState({});

  useEffect(() => {
    const details = shoesData.filter((shoeDetail) => {
      return shoeDetail.name == product_name;
    });

    setShoeDetails(details[0]);
  }, []);

  return (
    <Container maxW="100%" py={10}>
      <SimpleGrid columns={2} spacing={10}>
        <Box>
          <SimpleGrid columns={2} spacing={5}>
            {shoeDetails?.product_images?.map((img) => {
              return <Image src={img} />;
            })}
          </SimpleGrid>
        </Box>
        <Box w="100%">
          <Heading>{shoeDetails?.name}</Heading>
          <Heading size={"xl"} my={2} color="red">
            ${shoeDetails?.price}
          </Heading>
          <Text>{shoeDetails?.description}</Text>
        </Box>
      </SimpleGrid>
    </Container>
  );
};

export default ProductDetailsPage;

We are retrieving product details by getting the product_name and filtering it from data.

Now, our application is completed and we have set up routes and developed some components.

Start the application if you have not started earlier, by running npm start you can navigate through the pages, and you will experience that it will be fast as compared to the websites that build with only HTML, CSS, and JavaScript because there is no concept of 'client-side routing' there.

If you liked this article, consider following me on Hashnode for my latest publications.