Server-Side Rendering (SSR) is a technique used in web development to render web pages on the server instead of the client. This chapter will cover SSR from basic concepts to advanced techniques, providing a detailed understanding and practical examples. By the end of this chapter, you will have a comprehensive knowledge of SSR in React, its benefits, how it works, and how to implement it in your projects.
Server-Side Rendering (SSR) refers to the process of rendering web pages on the server rather than on the client. In SSR, the server generates the HTML content of the page, which is then sent to the client’s browser. This contrasts with Client-Side Rendering (CSR), where the rendering happens on the client after the initial HTML is loaded.
There are several reasons to use SSR in web applications:
In SSR, the server processes the React components and converts them into HTML before sending the response to the client. The client then receives the fully rendered HTML page and displays it. After the initial load, React takes over and manages subsequent updates to the DOM.
Here’s a simplified workflow of SSR:
To set up SSR with React, you typically use Node.js and a server framework like Express. Here’s a step-by-step guide to setting up a basic SSR application:
npx create-react-app ssr-example
cd ssr-example
npm install express react-dom/server
// server.js
const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const App = require('./src/App').default;
const app = express();
app.use(express.static('build'));
app.get('*', (req, res) => {
const app = ReactDOMServer.renderToString(React.createElement(App));
const html = `
SSR Example
${app}
`;
res.send(html);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
npm run build
node server.js
Now, when you navigate to http://localhost:3000
, you should see your React application rendered on the server.
In this example, we’ll create a simple React application that renders a welcome message on the server and sends the pre-rendered HTML to the client.
First, create a basic React application:
npx create-react-app ssr-basic-example
cd ssr-basic-example
Create an App.js
file inside the src
directory:
// src/App.js
import React from 'react';
function App() {
return (
Welcome to Server-Side Rendering with React
This is a basic example of SSR with React.
);
}
export default App;
Install Express and React DOM Server:
npm install express react-dom/server
Create a server.js
file in the root of your project:
// server.js
const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const App = require('./src/App').default;
const app = express();
app.use(express.static('build'));
app.get('*', (req, res) => {
const app = ReactDOMServer.renderToString( );
const html = `
SSR Example
${app}
`;
res.send(html);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Build the React application to generate the static assets:
npm run build
Start the server
node server.js
App
component to a string using ReactDOMServer.renderToString
and serves the HTML.http://localhost:3000
, the server sends the pre-rendered HTML, and you see the “Welcome to Server-Side Rendering with React” message immediately.In this example, we’ll create a React application that fetches data from an API on the server before rendering the component and sending the pre-rendered HTML to the client.
First, create a basic React application
npx create-react-app ssr-data-fetching-example
cd ssr-data-fetching-example
Create an App.js
file inside the src
directory:
// src/App.js
import React, { useState, useEffect } from 'react';
function App({ initialData }) {
const [data, setData] = useState(initialData);
useEffect(() => {
if (!initialData) {
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(json => setData(json));
}
}, [initialData]);
if (!data) {
return Loading...;
}
return (
{data.title}
{data.body}
);
}
export default App;
Install Express, React DOM Server, and node-fetch:
npm install express react-dom/server node-fetch
Create a server.js
file in the root of your project:
// server.js
const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const fetch = require('node-fetch');
const App = require('./src/App').default;
const app = express();
app.use(express.static('build'));
app.get('*', async (req, res) => {
const data = await fetch('https://jsonplaceholder.typicode.com/posts/1').then(response => response.json());
const app = ReactDOMServer.renderToString( );
const html = `
SSR Example with Data Fetching
${app}
`;
res.send(html);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Modify the index.js
file in the src
directory:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const initialData = window.__INITIAL_DATA__;
ReactDOM.hydrate( , document.getElementById('root'));
Build the React application to generate the static assets:
npm run build
Start the server:
node server.js
initialData
is provided, it uses that data; otherwise, it fetches the data on the client side.App
component to a string with the initial data, and serves the HTML.http://localhost:3000
, the server fetches the data from the API, pre-renders the App
component with the data, and sends the HTML to the client. The client hydrates the app with the initial data, and you see the content immediately.Code splitting allows you to load only the necessary code for a page, reducing the initial load time. Libraries like React.lazy
and React.Suspense
enable code splitting in React.
import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
Code Splitting with SSR
Loading... }>
Hydration is the process of attaching event listeners and making the static HTML interactive on the client side. React uses ReactDOM.hydrate
instead of ReactDOM.render
for this purpose.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.hydrate( , document.getElementById('root'));
Next.js is a popular framework for React that provides built-in support for SSR, static site generation (SSG), and more.
npx create-next-app ssr-next-example
cd ssr-next-example
import React from 'react';
function HomePage({ data }) {
return (
{data.title}
{data.body}
);
}
export async function getServerSideProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const data = await res.json();
return {
props: {
data,
},
};
}
export default HomePage;
getServerSideProps
fetches data on the server before rendering the page.Server-Side Rendering (SSR) is a powerful technique for improving the performance and SEO of React applications. By understanding how SSR works and implementing best practices, you can create fast, efficient, and search engine-friendly web applications.Happy coding !❤️