Pros and Cons of Client-side Routing with React
Apr 4, 2020 • 10 Minute Read
Introduction
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 and Rendering
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
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.
Pros
- Routing between components is fast as the amount of data that renders is less. The rest of the data is rendered by the DOM, and even when there's tons of HTML and CSS to render, the DOM handles that part in the blink of an eye. Using lazy loading, any delay in rendering HTML is compensated for.
- For better user experience, animations and transitions can be easily implemented when switching between different components.
- It gives a real sense of a single-page application in action. No separate pages are rendered, and the current page doesn't refresh to load a new view.
Cons
- The initial loading time is considerably large as all the routes, components, and HTML have to be loaded at once when the application first mounts . The whole website or web app needs to be loaded on the first request.
- There is unnecessary data download time for unusable views that cannot be anticipated on the first render of the application.
- It generally requires an external library, which means more code and more dependency on external packages, unlike routing on the server-side.
- Client-side routing and rendering convert JavaScript to HTML, making search engine crawling less optimized.
Client-side Routing in React
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
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.
Setting up
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:
npx 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:
import React from 'react';
function App() {
return (
<div className="App">
</div>
);
}
export default App;
Install the react-router-dom package using the following command inside the root directory:
npm install react-router-dom
Styles
Put the following styles inside index.css:
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.App {
max-width: 400px;
margin: 30px auto;
text-align: center;
}
nav{
padding: 5px;
background: rgb(151, 150, 150);
color: #ffffff;
}
nav ul {
padding: 0;
}
nav ul li {
display: inline-block;
margin: 0 10px;
cursor: pointer;
padding: 5px;
font-weight: 600;
}
.nav-link{
color: #ffffff;
text-decoration: none;
}
Creating the UI Components
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:
import React from 'react';
const About=()=>{
return(
<div className="about">
<h2>This is the about page</h2>
</div>
)
}
export default About;
Similarly, Contact.js will look like this:
import React from 'react';
const Contact=()=>{
return(
<div className="contact">
<h2>This is the contact page</h2>
</div>
)
}
export default Contact;
Finally, you can create the Home component in the same manner:
import React from 'react';
const Home=()=>{
return(
<div className="home">
<h2>This is the home page</h2>
</div>
)
}
export default Home;
The Router Module
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.
import React from 'react';
import Navbar from './Components/Navbar';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Home from './Components/Home';
import Contact from './Components/Contact';
import About from './Components/About';
function App() {
return (
<div className="App">
<BrowserRouter>
<Navbar/>
<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/contact" component={Contact}></Route>
<Route exact path="/about" component={About}></Route>
</Switch>
</BrowserRouter>
</div>
);
}
export 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.
import React from 'react';
import { Link } from 'react-router-dom';
const Navbar=()=>{
return(
<nav >
<ul>
<li><Link to="/" className="nav-link">Home</Link></li>
<li><Link to="/about" className="nav-link">About</Link></li>
<li><Link to="/contact" className="nav-link">Contact</Link></li>
</ul>
</nav>
)
}
export default Navbar;
Testing
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.
{
..//
"react-dom": "^16.13.1",
"react-router-dom": "^5.1.2",
..//
}
Conclusion
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.