Painting a masterpiece
Gradient background

Route to different pages in the application

Page 2 out of 9

In this chapter, you will use the react-router-dom to manage your routes and navigate to different pages using a navigation bar component.

Clarice Bouwer

Software Engineering Team Lead and Director of Cloudsure

Wednesday, 2 November 2022 · Estimated 4 minute read
Modified on Sunday, 13 November 2022

Objectives

  1. Add routes to each page in order to navigate to them.
  2. Create a navigation bar to render links for pages.

Dependency

You need to install an npm package called react-router-dom that will manage your routes in React for you.

bash
Copy
npm install react-router-dom

React Router is seemingly the most popular way to add page routing in React Apps. The video below offers:

  • A crash course for beginners.
  • Learning how to use React Router v6.

Create routes

You'll import a few things from react-router-dom. Checkout the docs to find out more about each one. You'll also be importing all the pages you need routes for. Your routing will be hooked up in index.js.

Each path is a route and it will render an element to render corresponding to a page when matched on. The path /* matches on any path and will render the NotFoundPage if that match does not match on any of the other Route paths specified.

:slug is a param in the URL segment that allows for variable content that we can access programmatically.

./src/index.js
Copy
// ... other imports
import {
  Route,
  RouterProvider,
  createBrowserRouter,
  createRoutesFromElements,
} from "react-router-dom";
import HomePage from './pages/Home';
import RegisterPage from './pages/Register';
import LoginPage from './pages/Login';
import ReviewPage from './pages/Review';
import NotFoundPage from './pages/NotFound';

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route>
      <Route path="/" element={<HomePage />} />
      <Route path="/*" element={<NotFoundPage />} />
      <Route path="/register" element={<RegisterPage />} />
      <Route path="/login" element={<LoginPage />} />
      <Route path="/review/:slug" element={<ReviewPage />} />
    </Route>
  )
);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Layout>
      <RouterProvider
        router={router}
        fallbackElement={<div>Loading....</div>}
      />
    </Layout>
  </React.StrictMode>,
);

// ... other code

You no longer need the App files so you can safely remove them.

bash
Copy
rm src/App.*

You will want to navigate to the different pages that you have created. In order to do so, create a navigation component with links to the different pages in it using the react-router-dom package.

bash
Copy
touch src/components/Navigation.js
./src/components/Navigation.js
Copy
import { Link } from 'react-router-dom';

const Navigation = () => {
  return (
    <nav>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/register">Register</Link>
        </li>
        <li>
          <Link to="/login">Login</Link>
        </li>
      </ul>
    </nav>
  );
};

export default Navigation;

The Navigation component uses the routes so it needs context to the RouterProvider. Change the Layout component to make render Outlet instead of the former children prop.

Use Outlet to render the element component associated with the path specified in index.js.

./src/Layout.js
Copy
import { Outlet } from 'react-router-dom';
import Navigation from './Navigation';

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

export default Layout;

The Navigation component relies on the RouterProvider in order to render correctly. Right now it's outside the provider.

Let's wrap the page inside the Layout component within the provider. Update the route element to render the Layout component and remove the Layout wrapper on RouterProvider.

./src/App.js
Copy
// ....

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route element={<Layout />}>
      <Route path="/" element={<HomePage />} />
      <Route path="*" element={<NotFoundPage />} />
      <Route path="register" element={<RegisterPage />} />
      <Route path="login" element={<LoginPage />} />
      <Route path="review/:slug" element={<ReviewPage />} />
    </Route>,
  ),
);

// ....

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouterProvider router={router} fallbackElement={<div>Loading....</div>} />
  </React.StrictMode>,
);

// ...

URL params

Create a fake in-memory data file for the interim. This data will be displayed in our app for the interim.

bash
Copy
mkdir src/data && touch src/data/reviews.json

Populate the file with random data.

./src/data/reviews.json
Copy
[
  {
    "slug": "1",
    "title": "Joe's Snack Shop",
    "abstract": "Lorem ipsum, dolor sit amet consectetur adipisicing elit.",
    "rating": 3.5
  },
  {
    "slug": "2",
    "title": "Gerry's TV",
    "abstract": "Lorem ipsum, dolor sit amet consectetur adipisicing elit.",
    "rating": 4.5
  },
  {
    "slug": "3",
    "title": "Pieter's Flower Shack",
    "abstract": "Lorem ipsum, dolor sit amet consectetur adipisicing elit.",
    "rating": 4.5
  }
]

Display the data in the Reviews page based on the URL. Render the Not Found page when there is no match on the data.

./src/pages/Review.js
Copy
import { useParams } from 'react-router-dom';
import NotFoundPage from './NotFound';
import data from '../data/reviews.json';

const ReviewPage = () => {
  const { slug } = useParams();
  const reviews = data.filter((i) => i.slug === slug);
  if (reviews.length > 0) {
    const review = reviews[0];
    return (
      <div>
        Review page <pre>{JSON.stringify(review, null, 2)}</pre>
      </div>
    );
  }

  return <NotFoundPage />;
};

export default ReviewPage;

Listing

Show all reviews on the home page and link through to the correct review page.

./src/pages/Home.js
Copy
import { Link } from 'react-router-dom';
import data from '../data/reviews.json';

const HomePage = () => {
  return data.map(({ slug, title, description, rating }) => {
    return (
      <div key={slug}>
        <h2>
          <Link to={`/review/${slug}`}>{title}</Link> / {rating}</h2>
        <p>{description}</p>
      </div>
    );
  });
};

export default HomePage;

Next steps

You will create a backend API that will contain logic to authenticate, rate and comment on things.

References