The Ultimate Beginner's Guide to React Router V6

A beginner friendly introduction to the crazy library

Last week I was scrolling through my twitter feed & I stumbled on an interesting tweet which seems to discuss React developer pain points. Among other things I noticed some folks talking about React Router and how crazy it is to wrap our heads around it. I've been there personally and get the frustration :)

image.png

This post is dedicated to everyone who is currently learning React & trying to get into the web development World.

Let's Go....

Background

React at its core is very good at rendering information & handling user events. React does this by making use of data (props and/or states) & renders information to the user. Additional logic can also be introduced in React components to handle user events and side effects.

If you have been doing React for sometime now, you will eventually be introduced to React's friends. Some of them worth mentioning here are

  1. Redux or similar state management libraries.
  2. Axios or some other data fetching libraries.
  3. React Router or similar routing libraries.

The focus of today's blog will be about the React Router. It is one of the most widely used and popular go to routing library. Shout out to all the maintainers who keep adding to the awesomeness with every major release.

The Need.

Let's say you are building a application which displays information useful to your end user in a simple view. The user can read up the stuff by scrolling down the one page and that is all. If yours is one such application you probably don't need React Router or any router for that matter. Just basic HTML, CSS and JS will get you there. In fact, You don't even need React or its peers.

However, the world we live in demands a lot more. Thanks to the power of the web. You as a developer could be tasked to design your application into different views/pages. You may need your end user to login to your application, do some fun stuff, have multiple pages/sections, design an application menu on click of which you go to some other feature/view. Some example of such applications are Amazon's Shopping site, your favorite food ordering site, social media sites etc.

Such application demand the need for dividing the application into multiple views/pages so that the user can easily "navigate" around the application. This is where we would need Routing.

It doesn't matter whether your application is single page application(SPA) or not, client side or server side rendered, mobile or web, you will need some sort of routing. React being a simple rendering library, it would need its "friends" to help with routing. To keep this blog simple, let's just focus on React Router for web applications with client side routing.

The main goal of any routing library is to keep the UI in sync when the URL changes.

Options

Here are some libraries using which we can do Routing for React applications.

  1. React Location
  2. Wouter
  3. React Router (Of course)
  4. and there are more.

Before we dive into the basics of React Router, we need to understand some basic concepts. Let's look at them first.

Concepts

  • URL: Uniform Resource Locator, The string on your address bar.

  • Browser Router- A type of router based on HTML 5 History API. Most widely used.

  • Link - Or simply a Hyperlink. Link is where the routing action begins.

  • Route - Defines a "path" and a "component". Points to a component which should be loaded to for a corresponding "path". keep the UI in sync with the URL .

  • Outlet - A place holder for nested routes. Usually present in a parent route. This is where child routes gets rendered. More on this soon.

If you do not understand some of these terms, do not worry, we will revisit them soon and things should become relatable.

React Router Setup/Installation

The below command will install React Router Library on your project. You can chose either npm or yarn as your package manager.

npm install react-router-dom  // yarn add react-router-dom

That is it ! Now you can start using React Router and add routing feature to your application. Yey !!!

Note: Here I am assuming you are familiar about how to install packages with Create-React-App or StackBlitz. I will be using codesandbox to code ( and I would recommend you to use the same if possible). All the next steps we perform will remain same whatever way you decide to start with.

Let's Code.

Let's warm up ourselves by writing some code.

Step 1: Preparation

Create three components, Home, Profile & About in the same folder containing app.js.

//home.js
const Home = () => {
  return (
    <div>
      <b>Welcome </b>
      <p>You are now in Home Component.</p>
    </div>
  );
};

export default Home;
//profile.js
const Profile = () => {
  return (
    <div>
      <b>Welcome </b>
      <p>You are now in Profile Component.</p>
    </div>
  );
};

export default Profile;
//about.js
const About = () => {
  return (
    <div>
      <b>Welcome </b>
      <p>You are now in About Us Component.</p>
    </div>
  );
};

export default About;

And your app.js could look like this..

import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <h1>React Router Example</h1>
    </div>
  );
}

Now, lets dive into the super cool stuff.

Step 2: Introducing React Router DOM to our application.

Ensure you have installed react-router-dom before proceeding next. You can check your package.json and it should have a similar entry for react-router-dom. Version may differ with time. The code in this blog will work with version 6.3.0.

image.png

  1. Navigate to index.js and import BrowserRouter from react-router-dom. BrowserRouter is a React Component.
  2. Add <BrowserRouter as the parent component of <App>.
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom"; // this

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <BrowserRouter> {/* And this */}
    <App />
  </BrowserRouter>
);

If you have an understanding of React's Context, you will find the above code quite comfortable. If not, all we are doing here is: by making BrowserRouter component as the parent of App component, the App component & its children gets access to routing.

Remember: With React, Data flows from top to bottom and events move from bottom to top.

Step 3: Bring in the Components

Remember the components we created in step 1, Let's include them into our index.js


import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";

import Home from "./home";   // This
import Profile from "./profile"; // This
import About from "./about"; // and This

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

Step 4: Define the Routes

This will be done in two steps.

  1. First import the Routes & Route from react-router-dom to index.js. Just like BrowserRouter, Routes & Route are also React components which accepts certain props & renders UI accordingly & also respond to events. Your import statement of index.js will now look like this.
import { BrowserRouter, Routes, Route } from "react-router-dom";
  1. Define the routes.
import { createRoot } from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";

import Home from "./home"; // This
import Profile from "./profile"; // This
import About from "./about"; // This

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <BrowserRouter>
    {/* From Here */}
    <Routes>
      <Route path="about" element={<About />}>
      <Route path="/" element={<App />}>
        <Route path="home" element={<Home />} />
        <Route path="profile" element={<Profile />} />
      </Route>
    </Routes>
    {/* Till Here */}
  </BrowserRouter>
);

Do not allow this code to trick your brain to think its "complicated". It is not. Here is what it is doing:

  1. Routes - Is a React Component. Simply think of them like a switch statement. This Component monitors changes to the address bar of the browser.

  2. Route - Also a React Component. Think of them as cases of a switch statement. The Route component takes path and element as props. The element prop's value can be any valid React Component & path props value is the location(a string).

  3. This is how things work: Whenever the path changes in the browser, the Routes component will look at all its children (<Route> ) and tries to find a match by comparing the URL location and path prop value. With this code, React Router Understands which component to load when the URL's path changes.

  4. With the code written above, we are instructing React Router to load App component when path is /. Similarly when the path changes to /about, About component will be loaded.

  5. Congratulations! This is all we need to bring in client side routing to our application.

  6. To make things a bit interesting, I have also introduced something called nested routes here. Were you able to identify? Do you see how the <Route> component with path "home" and "profile" is nested under <Route> component with path ="/"?

<Route path="/" element={<App />}>
        <Route path="home" element={<Home />} />
        <Route path="profile" element={<Profile />} />
</Route>

Lemme explain what is going on here by using this below line as example

        <Route path="home" element={<Home />} />

Here we are instructing React Router to load Home component when the path is /home. Why /home ? See the nesting. First the path is '/' and under that the path is 'home' and so when they are clubbed together, they form /home. Hence when the URL location is /home, Routes component will match the above path & so the components will be rendered.

Note that I mentioned components. It means both App and Home component gets rendered. For this to work, we just need to add one last piece to this puzzle. An <Outlet />.

7. Open your app.js and do the below change.

import "./styles.css";
import { Outlet } from "react-router-dom"; // This

export default function App() {
  return (
    <div className="App">
      <h1>React Router Example</h1>
      <Outlet /> {/* and this */}
    </div>
  );
}

Let's create a Menu component in the same folder as app.js and render it within app.js.

// menu.js
import { Link } from "react-router-dom";

const Menu = () => {
  return (
    <div>
      <Link style={{ margin: 10 }} to="/home">
        Home
      </Link>
      <Link style={{ margin: 10 }} to="/profile">
        Profile
      </Link>
      <Link style={{ margin: 10 }} to="about">
        About
      </Link>
    </div>
  );
};

export default Menu;

Let's understand the Link component from React Router by looking at this piece of code.

      <Link style={{ margin: 10 }} to="/home">
        Home
      </Link>

This Link component simply creates a hyperlink as below and that is all it does. When you click on the link, the HTML anchor tag changes/updates the location or path.

<a href="/home" style="margin: 10px;">Home</a>

The same thing will also happen for the other two Links defined in the Menu Component.

2. Let's render Menu component inside app.js. That should be straight forward.

import "./styles.css";
import { Outlet } from "react-router-dom";
import Menu from "./menu"; // This

export default function App() {
  return (
    <div className="App">
      <h1>React Router Example</h1>
      <Menu />  {/* and this */}
      <hr /> {/* and this to create a separation visually */}
      <Outlet />
    </div>
  );
}

Step 5: Let's take our code for a spin.

This is how your page should look like now.

image.png


Click on Home to get the below output. (Observe how the address bar now has /home)

image.png


Click on Profile to get the below output. Remember to observe the address bar.

image.png


Now, Click on About to for a surprise..

image.png

Well, that looks different now isn't it. We dont see the menu any more since About is not a nested route. So it replaces the entire App component with its content. We can improve this situation by introducing a <Link> from react-router-dom inside About component and give this <Link> component a value of \ to the path prop. That is it. With this, you can now navigate back to the App Component.

The code change for this is left to the reader as an exercise. All the hints you need is provided just above. If you did this change, your output should looks something similar.

image.png


Step 6: Summary.

Here is a quick summary of how everything works.

  1. To begin with, index.js has a default path of '/'. This will match the route defined as <Route path="/" element={<App />}>

  2. So renders the <App /> component which contains the Menu component.

  3. The <Menu /> component contains the Links. Remember Links are basically HTML anchor tags. So on click of these links, the browser address will change. Say you clicked on Profile link.

  4. This will change the browser's address from '/' to '/profile'.

  5. <Routes> component keeps an eye on changes to the address bar. When there is a change, it tries to find the Route to match the current location. Remember the switch cases.

  6. <Routes> components finds a matching route defined as <Route path="profile" element={<Profile />} /> and so renders the <Profile> component.

  7. Oh, that is it. As simple as that :)


Here is the completed final code for your reference.

There is so much more to React Router.

  1. Handling Invalid paths
  2. Reading query string parameters
  3. Rendering layouts
  4. Dynamic routing
  5. Server side rendering etc.

I will write another blog around these topics. Watch out for this space.

Connect with me & say hello here


I mentor students/working professionals on Javascript & React for Free over the weekends. If you are interested, you can register for free here. Next batch starts Aug 06th, 2022, Saturday 10 AM IST.



Until next time.




Did you find this article valuable?

Support Sandeep Gokhale by becoming a sponsor. Any amount is appreciated!