Boost Performance With React Server Components and Next.js

Wait 5 sec.

React is one of the most popular tools for building modern web applications. If you’ve worked with React, you’ve probably heard of components — small, reusable pieces of code that create parts of a webpage, like buttons, forms, or headers. However, in 2020, the React team introduced something exciting called React Server Components (RSCs), a new way to build faster and more efficient web apps.React Server Components were introduced to address the inefficiencies in traditional client-side rendering and server-side rendering, such as large JavaScript bundles and redundant client-server data fetching.In this blog post, we’ll dive deep into React Server Components, why they’re fantastic, and how you can use them to create a dynamic e-commerce product listing page. By the end, you’ll clearly understand RSCs and a practical example to get you started. Let’s jump in!What Are React Server Components?React Server Components (RSCs) are a new type of React component that runs only on the server. Unlike traditional React components, which run in the user’s browser (client-side), RSCs execute on the server and send the results to the browser. This means they can directly access server-side resources like databases, file systems, or APIs without needing extra client-side code.Imagine you’re building an online store. To show a list of products, a traditional React app would:Load the webpage in the browser.Make an API call from the browser to the server to fetch product data.Display the products once the data arrives.With React Server Components, the server can fetch the product data and render the component before sending the page to the browser. This makes the page load faster and reduces the amount of JavaScript sent to the client.Unlike SSR (Server-Side Rendering), RSCs don’t require hydration for every component, meaning they can render HTML on the server without sending unnecessary JavaScript to the client.Why Are RSCs Important?RSCs bring many benefits that make web apps faster, simpler, and more efficient. Here are the key advantages:Faster Page Loads: Since RSCs run on the server, the browser gets pre-rendered HTML immediately. Users see content faster without waiting for JavaScript to fetch data.Less JavaScript in the Browser: RSCs reduce the amount of JavaScript sent to the client, which is excellent for performance, especially on slower devices or networks.Direct Server Access: RSCs can talk directly to databases or APIs on the server, making your code more straightforward and secure.Better Developer Experience: With RSCs, you can write server and client logic in the same React component model, keeping your codebase clean and consistent.How Do React Server Components Work?To understand RSCs, let’s break down how they fit into a React app. A typical React app with RSCs has two types of components:Server Components: These run only on the server. They can fetch data, access files, or perform heavy computations. Because they don’t run in the browser, they don’t include interactive features like onClick handlers.Client Components: These are the traditional React components that run in the browser. They handle interactivity, like button clicks or form inputs.Note: RSCs are part of React’s effort to split rendering responsibilities between server and client more efficiently. They allow the client to stay lightweight while the server handles data-intensive tasks.Server Components are rendered on the server, and their output (HTML or a special format React uses) is sent to the browser. If a server component includes a client component, React knows how to send the necessary JavaScript for the client component to the browser.React uses use client and use server directives to distinguish between component types. While use client is explicitly required for client components, server components are server by default — but you can also mark a file with use server to clarify intent or enforce placement.The “.server.js” and “.client.js” FilesIn a project using RSCs, you’ll see files with special extensions:.server.js: Indicates a Server Component that runs only on the server..client.js: Indicates a Client Component that runs in the browser.For example:ProductList.server.js: A Server Component fetches product data from a database and renders a list.AddToCartButton.client.js: A Client Component with a button that adds a product to the cart when clicked.React’s build tools (like Next.js) use these extensions to decide where each component should run.Building an E-Commerce Product Listing Page with RSCsLet’s walk through a practical example of using React Server Components to build a product listing page for an online store. We’ll use Next.js 13 (or later), which significantly supports RSCs. This example assumes you have some basic knowledge of React and Next.js, but I’ll keep it simple.Step 1: Set Up Your Next.js ProjectFirst, create a new Next.js project. Open your terminal and run:npx create-next-app@latest my-ecommerce-appcd my-ecommerce-appnpm run devThis sets up a Next.js app and starts a development server at http://localhost:3000. Next.js’s App Router (introduced in Next.js 13) supports RSCs out of the box.Step 2: Create a Server Component for the Product ListLet’s create a Server Component that fetches a list of products from a mock database (we’ll use a JSON file for simplicity). Create a new file at app/products/ProductList.server.js:// app/products/ProductList.server.jsimport products from '../../data/products.json';export default async function ProductList() {  // Simulate fetching data from a database  const productData = await new Promise((resolve) => {    setTimeout(() => resolve(products), 500); // Fake delay  });  return (          Our Products              {productData.map((product) => (                      {product.name}            Price: ${product.price}            {product.description}                  ))}            );}Create a mock database file at data/products.json:[  {    "id": 1,    "name": "Wireless Headphones",    "price": 99.99,    "description": "High-quality wireless headphones with noise cancellation."  },  {    "id": 2,    "name": "Smart Watch",    "price": 149.99,    "description": "Track your fitness and stay connected on the go."  },  {    "id": 3,    "name": "Portable Charger",    "price": 29.99,    "description": "Compact charger for your devices."  }]This Server Component fetches the product data and renders a list. The async keyword is used because RSCs can handle asynchronous operations like fetching data.Step 3: Create a Client Component for InteractivityNow, let’s add a button to each product that adds it to a cart. Since buttons are interactive, this needs to be a Client Component. Create a file at app/products/AddToCartButton.client.js:// app/products/AddToCartButton.client.js'use client'; // Marks this as a Client Componentexport default function AddToCartButton({ productId }) {  function handleClick() {    alert(`Added product ${productId} to cart!`);    // In a real app, you'd update a cart state or make an API call  }  return (          Add to Cart      );}The “use client” directive tells Next.js that this is a Client Component. It runs in the browser and can handle events like onClick.Step 4: Combine Server and Client ComponentsUpdate the ProductList.server.js to include the AddToCartButton:// app/products/ProductList.server.jsimport products from '../../data/products.json';import AddToCartButton from './AddToCartButton.client';export default async function ProductList() {  const productData = await new Promise((resolve) => {    setTimeout(() => resolve(products), 500);  });  return (          Our Products              {productData.map((product) => (                      {product.name}            Price: ${product.price}            {product.description}                              ))}            );}Now, the Server Component renders the product list, and each product includes an interactive AddToCartButton that runs in the browser.Step 5: Create a Page to Display the Product ListIn Next.js, pages are created in the app directory. Create a file at app/products/page.js:// app/products/page.jsimport ProductList from './ProductList.server';export default function ProductsPage() {  return (                );}This page renders the ProductList Server Component. Visit http://localhost:3000/products in your browser, and you’ll see a list of products with “Add to Cart” buttons. Clicking a button will show an alert (in a real app, you’d update a cart).Step 6: Style the Page (Optional)To make the page look better, add some CSS. Create a file at app/globals.css and update it:/* app/globals.css */body {  font-family: Arial, sans-serif;  margin: 0;  padding: 20px;}h1 {  color: #333;}ul {  list-style: none;  padding: 0;}li {  border: 1px solid #ddd;  padding: 15px;  margin-bottom: 10px;  border-radius: 5px;}button {  background-color: #28a745;  color: white;  border: none;  padding: 8px 16px;  border-radius: 4px;  cursor: pointer;}button:hover {  background-color: #218838;}This adds basic styling to make the product list look clean and professional.Why This Example Is AwesomeThis e-commerce product listing page showcases the power of React Server Components:Performance: The product list is rendered on the server, so users see content quickly, even on slow networks.Simplicity: The Server Component fetches data directly, reducing the need for complex client-side logic.Interactivity: The Client Component (AddToCartButton) adds interactivity where needed, keeping the browser lightweight.Scalability: In a real app, you could replace the JSON file with a database query (e.g., Prisma or MongoDB) without changing the component structure.Advanced Features of RSCsOnce you’re comfortable with the basics, here are some advanced ways to use RSCs:Streaming RenderingRSCs support streaming, which means the server can send parts of the page to the browser as they’re ready. For example, in an e-commerce app, you can immediately show the header, filters, and categories while the product grid streams behind the scenes, offering a smoother user experience. If fetching products takes time, you can immediately show a header or navigation bar while the product list loads. Next.js makes this easy with the Suspense component:import { Suspense } from 'react';import ProductList from './ProductList.server';export default function ProductsPage() {  return (          Online Store                          );}The fallback content (e.g., “Loading products…”) shows until the ProductList is ready.Dynamic Data FetchingYou’d fetch data from a database or API in a real app. For example, with a PostgreSQL database and Prisma:// app/products/ProductList.server.jsimport { PrismaClient } from '@prisma/client';const prisma = new PrismaClient();export default async function ProductList() {  const products = await prisma.product.findMany();  return (          Our Products              {products.map((product) => (                      {product.name}            Price: ${product.price}            {product.description}                              ))}            );}This fetches products directly from a database, keeping the logic server-side.Server-Only LogicRSCs can handle sensitive operations, like checking user permissions or accessing private APIs, without exposing secrets to the client. For example:// app/admin/Dashboard.server.jsimport { getCurrentUser } from '../../lib/auth';export default async function AdminDashboard() {  const user = await getCurrentUser();  if (!user.isAdmin) {    throw new Error('Access denied');  }  return Welcome, Admin!;}This ensures only authorized users see the dashboard, and the logic stays on the server.Challenges and Limitations of RSCsWhile RSCs are powerful, they have some limitations:Server Dependency: Your app needs a server to run RSCs, so they don’t work in fully static sites (e.g., exported Next.js sites).Learning Curve: Mixing Server and Client Components can be confusing at first. You need to understand where the code runs.No Interactivity in Server Components: If you need interactivity (e.g., onClick), you must use a Client Component.Tooling Requirements: RSCs require a framework like Next.js and a compatible build setup.Despite these challenges, the performance and simplicity benefits make RSCs worth learning.React Server Components are still experimental and best supported in frameworks like Next.js 13+. To avoid unexpected issues, it’s essential to keep your project dependencies aligned with the latest stable versions.Tips for Using RSCs EffectivelyHere are some best practices to get the most out of RSCs:Minimize Client Components: Use Server Components for static or data-heavy parts of your app to reduce JavaScript sent to the browser.Leverage Suspense: Use Suspense for streaming to improve perceived performance.Keep Components Small: Break down complex components into smaller Server and Client Components for clarity.Test Performance: Use tools like Lighthouse to measure how RSCs improve your app’s load time and user experience.Stay Updated: RSCs are still evolving, so follow React and Next.js updates for new features and best practices.Monitoring tools like Lighthouse or Chrome DevTools can be used to benchmark the performance gained from RSC adoption.ConclusionReact Server Components are a game-changer for building fast, efficient, and scalable web applications. By running components on the server, RSCs reduce client-side JavaScript, speed up page loads, and simplify data fetching. Our e-commerce product listing example showed how to combine Server and Client Components to create a dynamic, interactive page with minimal effort.If you’re new to RSCs, start small with a project like the one we built here. Experiment with Next.js, try fetching data from a real database, and explore streaming with Suspense. As you get comfortable, RSCs make your apps faster and your code cleaner.The post Boost Performance With React Server Components and Next.js appeared first on The New Stack.