In layman's terms, the performance on the frontend of a website is directly affected by things like the number of pages loaded initially, the amount of data fetched and displayed, and the time taken to switch from one page to another. Client-side rendering and routing give a subtle sense performance of your application, and it's essential to use the power of your frontend framework to your advantage. This guide explores the advantages and disadvantages of client-side routing and shows how to implement it in React.
Routing is the process through which the user is navigated to different pages on a website. Rendering is the process of putting those pages on the UI. Every time you request a route to a particular page, you are also rendering that page, but not every render is an outcome of a route. Their close association helps in speculating their effect on the efficiency and speed of an application.
Client-side routing is handled solely by JavaScript on the page. Whenever a user clicks on a link, the URL bar changes and a different view is rendered on the page. This view could be anything—JSX or HTML. Single-page applications give a smooth sense of navigation as they don't refresh the whole page when a route is performed. Even when a request is made to the server to fetch data, it only seems as if static HTML pages are rendered on the frontend. Thus, single-page applications are direct beneficiaries of client-side routing, and this is one major reason for their growing popularity and delivery of great user experience.
Let's look at the pros and cons of client-side routing.
React renders the appropriate information on the DOM using its component structure. Client-side routing in React helps to maintain the seamless user experience that a typical single-page application promises. This is 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. This also means that all the required components are also rendered without any flashes of white screen or page reload.
Make sure you have Nodejs
and npm
installed on your machine (at least version 8 or higher) along with a code editor and a web browser (preferably Chrome or Firefox).
Create a new project using create-react-app
:
1npx create-react-app react-routing
Clean up the project template by removing logo.svg
, all its relevant imports, and some boilerplate inside App.js
. Your App.js
should look like this:
1import React from 'react';
2
3function App() {
4 return (
5 <div className="App">
6
7 </div>
8 );
9}
10
11export default App;
Install the react-router-dom
package using the following command inside the root directory:
1npm install react-router-dom
Put the following styles inside index.css
:
1body {
2 margin: 0;
3 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 sans-serif;
6 -webkit-font-smoothing: antialiased;
7 -moz-osx-font-smoothing: grayscale;
8}
9
10.App {
11 max-width: 400px;
12 margin: 30px auto;
13 text-align: center;
14}
15
16nav{
17 padding: 5px;
18 background: rgb(151, 150, 150);
19 color: #ffffff;
20}
21nav ul {
22 padding: 0;
23}
24nav ul li {
25 display: inline-block;
26 margin: 0 10px;
27 cursor: pointer;
28 padding: 5px;
29 font-weight: 600;
30}
31
32.nav-link{
33 color: #ffffff;
34 text-decoration: none;
35}
All UI components will render an <h2>
indicating which component is currently rendered by that route.
Simply import React from the core, create a stateless functional component, and make sure to export it in the end. This is how About.js
should look:
1import React from 'react';
2
3const About=()=>{
4 return(
5 <div className="about">
6 <h2>This is the about page</h2>
7 </div>
8 )
9}
10
11export default About;
Similarly, Contact.js
will look like this:
1import React from 'react';
2
3const Contact=()=>{
4 return(
5 <div className="contact">
6 <h2>This is the contact page</h2>
7 </div>
8 )
9}
10
11export default Contact;
Finally, you can create the Home
component in the same manner:
1import React from 'react';
2
3const Home=()=>{
4 return(
5 <div className="home">
6 <h2>This is the home page</h2>
7 </div>
8 )
9}
10
11export default Home;
The three important components of the Router Module are <BrowserRouter/>
, <Switch/>
, and <Route/>
.
Everything inside <BrowserRouter/>
indicates information about Routing. It's a wrapper component for all the components that will be using client-side routing to render themselves, and it informs React about that.
<Switch/>
ensures that only one route is handled at a time, and the <Route/>
component tells us which component will be rendered on which route.
For a large application, it's more logical to create a separate component, but for now, it's convenient to put all routes inside App.js
.
1import React from 'react';
2import Navbar from './Components/Navbar';
3import { BrowserRouter, Switch, Route } from 'react-router-dom';
4import Home from './Components/Home';
5import Contact from './Components/Contact';
6import About from './Components/About';
7
8function App() {
9 return (
10 <div className="App">
11 <BrowserRouter>
12 <Navbar/>
13 <Switch>
14 <Route exact path="/" component={Home}></Route>
15 <Route exact path="/contact" component={Contact}></Route>
16 <Route exact path="/about" component={About}></Route>
17 </Switch>
18 </BrowserRouter>
19 </div>
20 );
21}
22
23export default App;
The <Route/>
tag takes in two props. One is path
, which simply takes a string indicating the route for that component and a component
prop that outputs that component or renders it when the user goes to that particular route. The exact
property ensures that the component is rendered only when the route matches the exact string mentioned in the path and no substring or superstring of that route will be able to render that component.
Lastly, to ensure that these routes are triggered from the UI, set up these routes inside Navbar.js .
Instead of the traditional anchor (<a/>
) tag, react-router-dom
provides us with the <Link/>
tag, which works exactly like the anchor tag but prevents the default page reloading action.
1import React from 'react';
2import { Link } from 'react-router-dom';
3
4const Navbar=()=>{
5 return(
6 <nav >
7
8 <ul>
9 <li><Link to="/" className="nav-link">Home</Link></li>
10 <li><Link to="/about" className="nav-link">About</Link></li>
11 <li><Link to="/contact" className="nav-link">Contact</Link></li>
12 </ul>
13 </nav>
14 )
15}
16
17export default Navbar;
Run npm start
to spin a local development server. You can see the app up and running on localhost:3000 in your browser (create-react-app
automatically does this for you ). You can click the different navigation links on the navbar to see how each component renders when its corresponding route is initiated.
Note that the version of react-router-dom
used in this example is v. 5. If you get any depreciated warnings or errors, you can use the exact version of this library used in this guide by updating your package.json
file and running the command npm i
.
1{
2 ..//
3
4 "react-dom": "^16.13.1",
5 "react-router-dom": "^5.1.2",
6
7 ..//
8
9}
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. If you're using a backend-less application or a backend service such as firebase, it can speed up your single-page Application, providing seamless user experience. Conventional server-side rendering can outperform it in various situations, so it is important to understand the needs of your application and decide whether to use client-side routing, server-side routing, or a combination of both.