DEV Community

jaredsurya
jaredsurya

Posted on

Client-side Routing on a React-based SPA

- WHAT IS SPA?

From mdn web docs:

An SPA (Single-page application) is a web app implementation that loads only a single web document, and then updates the body content of that single document via JavaScript APIs such as XMLHttpRequest and Fetch when different content is to be shown.

This therefore allows users to use websites without loading whole new pages from the server, which can result in performance gains and a more dynamic experience, with some tradeoff disadvantages such as SEO, more effort required to maintain state, implement navigation, and do meaningful performance monitoring.One helpful feature we can incorportate into our Single Page Applications is client-side routing. Single-page applications have, by definition, only one HTML document for the entire application, thus they are a perfect candidate for client-side routing. If we choose to use client-side routing to develop our page, all of the routing logic will be handled within Javascript. Also, the initial page-loading process happens with a single GET request to the backend server. After that, GET requests may be only needed for supplementary data. The bulk of the application will be loaded and the client-side routing will take control of switching which components are shown, how, and when. Routing consists of changing what the client is receiving in the web browser based on the endpoint of a URL. Not having to send a GET request on every routing call means that pages using client-side routing methods will render faster. As one of the essential aspects of single-page applications and as React doesnโ€™t come with a routing solution, React developers must integrate third-party libraries to implement routing into their applications.

- HOW CLIENT-SIDE ROUTING WORKS IN REACT:
The general difference between client-side routing and server-side rendering is in which part of the website is the routing/rendering happening. The client-side would have the application programmatically adjust what the user is seeing based on logic in the browser that is affecting the user - experience. With the other, server-side routing, the user makes requests to the server every time there is to be a change to the app screen. With react, client-side routing is preferred. React receives a user request and programmatically renders the appropriate information on the DOM based on its component structure. Client-side routing in React helps to maintain the seamless user experience that a typical single-page application can promise. This may be achieved through an external React library called React Router. React Router uses dynamic routing to ensure that routing is achieved as it is requested by the user. Using React Router means that all the required components are also rendered without any flashes of white screen or page reload. All of this client-side routing produces speedy webpages and a seamless user experience.

- HOW REACT ROUTER CAN AID IN CLIENT-SIDE ROUTING:
In the following notes, I will briefly elaborate on some of the the basics of how React Router works. For steps to install React Router, click here. Once React Router has been installed, we would import BrowserRouter and wrap the entire App component in it to render it.

import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

const root = ReactDOM.createRoot(
  document.getElementById("root")
);
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
Enter fullscreen mode Exit fullscreen mode

Within App.js, we import 'Link' and add some global navigation:

import { Link } from "react-router-dom";

export default function App() {
  return (
    <div>
      <h1>Bookkeeper</h1>
      <nav>
        <Link to="/invoices">Invoices</Link> |{" "}
        <Link to="/expenses">Expenses</Link>
      </nav>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

At this point there aren't any routes that render when the URL changes yet, but Link is changing the URL without causing a full page reload.๐Ÿ‘

Now, we'll render some new components to be routed to:

Expenses:

export default function Expenses() {
  return (
    <main style={{ padding: "1rem 0" }}>
      <h2>Expenses</h2>
    </main>
  );
}

Enter fullscreen mode Exit fullscreen mode

Invoices:

export default function Invoices() {
  return (
    <main style={{ padding: "1rem 0" }}>
      <h2>Invoices</h2>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Next, inside of Index.js we'll create our first route config. By setting the path for each element we effectively tell the DOM what component has to be loaded if the specific URL path is chosen. We'll make it so that at "/" it renders and at "/invoices" it renders :

import ReactDOM from "react-dom/client";
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";

const root = ReactDOM.createRoot(
  document.getElementById("root")
);
root.render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />} />
      <Route path="expenses" element={<Expenses />} />
      <Route path="invoices" element={<Invoices />} />
    </Routes>
  </BrowserRouter>
);
Enter fullscreen mode Exit fullscreen mode

As you can see, we import Route in order to make each url path, and Routes as a container for them all.

The next thing we will have to do is create a Link for the client to click on and navigate the page:

import { Link, Outlet } from "react-router-dom";
import { getInvoices } from "../data";

export default function Invoices() {
  let invoices = getInvoices();
  return (
    <div style={{ display: "flex" }}>
      <nav
        style={{
          borderRight: "solid 1px",
          padding: "1rem",
        }}
      >
        {invoices.map((invoice) => (
          <Link
            style={{ display: "block", margin: "1rem 0" }}
            to={`/invoices/${invoice.number}`}
            key={invoice.number}
          >
            {invoice.name}
          </Link>
        ))}
      </nav>
      <Outlet />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Above we see the Link components being made as the invoices array is mapped through, producing one Link of appropriate parameters per invoice. When the Link is clicked by someone navigating the website, the React Router would render that component. The URL would also show that we were viewing that page.

You can demo a working version of this app here.

For a somewhat broader overview of what's possible with React Router, as well as some more how-to, visit this page.

React Router and other libraries like it are so brilliant because they take complex programmatic issues and have worked through them to enable a solution which makes many web pages run much faster. Client-side routing is hugely impactful as a means of navigating many webpages. The webpage user gets a streamlined experience in a quicker way than ever before.
To go even more in depth to the concepts which make React Router run, click here!

Client-side routing can provide a great performance benefit if your application consists mainly of a static page or if it's a landing page for your company. And, you're using a backend-less application, it can speed up your single-page application and provide seamless user experience. Since conventional server-side rendering can out-perform client-side routing in various situations, it's still important to understand the needs of your application. With this knowledge, you can decide whether to use client-side routing, server-side routing, or a combination of both.

Top comments (0)