top of page
Search

Using Server-Side Rendering (SSR) with React in Next.js: A Complete Example

Using Server-Side Rendering (SSR) with React in Next.js: A Complete Example


This article provides a complete example of implementing Server-Side Rendering (SSR) with React in Next.js using TypeScript, including both server-side and client-side code.  We'll build a simple product details page, demonstrating how data fetched on the server is used to render the component on the client.


Why SSR?


SSR offers improved SEO, faster FCP, and better performance, especially on slower devices.


Project Setup (if you haven't already):


```bash

npx create-next-app@latest my-next-app --typescript

cd my-next-app

```


File Structure:


```

my-next-app/

├── pages/

│   └── products/

│       └── [id].tsx     // Product details page (SSR logic here)

├── types/

│   └── product.d.ts   // Product interface

├── components/          // Reusable React components (optional)

│   └── ProductDisplay.tsx // Component to display product details

├── public/              // Static assets

├── styles/             // CSS or other styling

├── ... other files ...

```


1. Define the Product Interface (`types/product.d.ts`):


```typescript

interface Product {

  id: number;

  name: string;

  description: string;

  price: number;

  image: string;

}

```


2. Product Display Component (`components/ProductDisplay.tsx`):


```typescript

import Image from 'next/image';

import React from 'react';


interface ProductDisplayProps {

  product: Product;

}


const ProductDisplay: React.FC<ProductDisplayProps> = ({ product }) => {

  return (

    <div>

      <h1>{product.name}</h1>

      <Image src={product.image} alt={product.name} width={500} height={500} />

      <p>{product.description}</p>

      <p>Price: ${product.price}</p>

    </div>

  );

};


export default ProductDisplay;

```


3. Product Details Page (`pages/products/[id].tsx`):


```typescript

import { GetServerSideProps } from 'next';

import React from 'react';

import ProductDisplay from '../../components/ProductDisplay'; // Import the component


interface ProductDetailsProps {

  product: Product | null;

  error: string | null;

}


const ProductDetails: React.FC<ProductDetailsProps> = ({ product, error }) => {

  if (error) {

    return <div>Error: {error}</div>;

  }


  if (!product) {

    return <div>Loading...</div>;

  }


  return (

    <div>

      <ProductDisplay product={product} /> {/* Use the component */}

    </div>

  );

};


export const getServerSideProps: GetServerSideProps<ProductDetailsProps> = async (context) => {

  const { id } = context.params;


  try {

    const res = await fetch(`https://fakestoreapi.com/products/${id}`); // Replace with your API

    if (!res.ok) {

      throw new Error(`HTTP error! status: ${res.status}`);

    }

    const product: Product = await res.json();


    return {

      props: {

        product,

        error: null,

      },

    };

  } catch (err: any) {

    console.error("Error fetching product:", err);

    return {

      props: {

        product: null,

        error: err.message,

      },

    };

  }

};


export default ProductDetails;

```


4. Explanation:


  *`pages/products/[id].tsx`:** This is our product details page. The `[id]` part makes it a dynamic route (e.g., `/products/1`, `/products/2`, etc.).

  *`ProductDisplay` Component:** This reusable component displays the product details.  Separating this logic makes the code more organized.

  *`getServerSideProps`:**

      Fetches product data from the API on the server*.

    *   Handles errors during the fetch.

    *   Passes the fetched data as props to the `ProductDetails` component.

  *`ProductDetails` Component:**

    *   Receives the `product` and `error` props.

    *   Renders the `ProductDisplay` component, passing the `product` data.  It also handles the loading and error states.

  *TypeScript Interfaces:**  `Product` and `ProductDetailsProps` provide type safety.


5. How it Works (Client-Server Interaction):


1.  User requests `/products/1`.

2.  Next.js calls `getServerSideProps` on the server.

3.  `getServerSideProps` fetches product data from the API.

4.  Next.js renders the `ProductDetails` component (and the nested `ProductDisplay` component) on the server, generating HTML.

5.  The server sends the HTML to the client's browser.

6.  The browser displays the HTML immediately (fast FCP).

7.  React hydrates the HTML on the client, making it interactive.  If the user navigates to another product page, the process repeats from step 2.


6. Running the Application:


```bash

npm run dev

```


Visit `http://localhost:3000/products/1` (or other product IDs).


Key Improvements:


  *Reusable Component:** The `ProductDisplay` component makes the code more modular and maintainable.

  *Clearer Data Flow:**  Data fetching is separated from data display.

  *Complete Example:** Shows the full interaction between server-side and client-side code.

  *Organized File Structure:**  Follows best practices for organizing Next.js projects.


This complete example provides a solid foundation for building more complex SSR applications in Next.js with React and TypeScript.  Remember to replace the example API URL with your actual API endpoint.  You can extend this example by adding more features like error handling, loading indicators, and styling.

 
 
 

Recent Posts

See All
What we can learn from cats

That's a fascinating observation, and you've touched upon something quite profound about the apparent inner peace that some animals seem...

 
 
 

Commentaires


Post: Blog2_Post

Subscribe Form

Thanks for submitting!

©2020 by LearnTeachMaster DevOps. Proudly created with Wix.com

bottom of page