How to Implement Client-Side Rendering in React
This article provides a straightforward guide on how to implement Client-Side Rendering (CSR) in React. You will learn the core mechanics of CSR, how to set up a standard React application that renders entirely in the browser, and how to manage key aspects of client-side apps, such as routing and data fetching.
Understanding Client-Side Rendering in React
In Client-Side Rendering (CSR), the server sends a bare-minimum HTML
document to the browser, usually containing just a single
<div> container and a link to a JavaScript bundle.
The browser downloads this bundle, and React executes to generate the
DOM nodes, handle user interactions, and fetch data dynamically.
By default, standard React applications built with bundlers like Vite or Create React App use CSR.
Step 1: Set Up a React Project
The fastest way to implement a CSR React application is by using Vite, which sets up a highly optimized development environment.
Run the following commands in your terminal:
npm create vite@latest my-csr-app -- --template react
cd my-csr-app
npm install
npm run devThis creates a pre-configured React project designed for client-side rendering.
Step 2: Analyze the HTML and Entry Points
Open the project in your code editor. In a CSR architecture, the application relies on two main files to render:
index.html: Located in the root folder. It contains a minimal structure:<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>React CSR App</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.jsx"></script> </body> </html>src/main.jsx: This is the entry point where React mounts your component tree onto the HTML DOM container.import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <App /> </React.StrictMode>, )
When a user visits your site, they receive this empty
index.html. The browser then executes the
main.jsx bundle to inject the <App />
component into the <div id="root"> element.
Step 3: Implement Client-Side Routing
Because CSR apps run entirely in the browser, navigating to a new page must not trigger a full server refresh. Instead, you use a client-side router to update the URL and swap components dynamically.
Install React Router:
npm install react-router-domConfigure the router in src/App.jsx:
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function Home() {
return <h1>Home Page</h1>;
}
def About() {
return <h1>About Page</h1>;
}
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link> | <Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
export default App;This setup intercepts browser navigation events and updates the view immediately without requesting new HTML pages from the server.
Step 4: Handle Data Fetching
In a CSR application, data is fetched after the initial page has
loaded. This is typically handled within the component lifecycle using
the useEffect hook.
Here is an example of fetching data from an API inside a CSR component:
import { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) {
return <p>Loading data...</p>;
}
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default UserList;When this component mounts, it displays a loading state, fetches the data on the client side, and updates the UI once the data is ready.