React LogoServer-Side Rendering (SSR - Next.js)

Server-Side Rendering (SSR) is a rendering technique where a web page is generated on the server for each request, rather than entirely in the browser. Next.js, a popular React framework, offers first-class support for SSR, allowing developers to build performant and SEO-friendly React applications.

How SSR Works in Next.js:
When a user requests an SSR page in a Next.js application, the following happens:
1. The browser sends a request to the Next.js server.
2. The server executes a special asynchronous function called `getServerSideProps` (if defined) on the requested page.
3. Inside `getServerSideProps`, you typically fetch data from an external API, a database, or perform any server-side logic required for the page. This function runs exclusively on the server.
4. The data returned by `getServerSideSideProps` is then passed as `props` to the React component for that page.
5. The Next.js server renders the React component into a full HTML string, embedding the fetched data directly into the HTML.
6. This pre-rendered HTML, along with the necessary JavaScript to "hydrate" the page (making it interactive on the client-side), is sent back to the browser.
7. The browser receives and displays the fully formed HTML immediately. Once the JavaScript loads, React takes over, making the page interactive.

Benefits of SSR (Next.js):
* Improved SEO: Search engine crawlers can easily parse the fully rendered HTML content, leading to better indexing and ranking compared to client-side rendered (CSR) applications which often present an empty HTML shell initially.
* Faster Initial Page Load: Users see content on the screen much faster because the browser receives pre-rendered HTML, reducing the "time to first paint" and "first contentful paint."
* Better Performance for Slower Networks/Devices: Since most of the rendering work is done on the server, less processing is required on the client side, which benefits users with older devices or slower internet connections.
* Dynamic Data on Every Request: SSR is ideal for pages that need to display frequently updated data or user-specific information that changes with every request, as `getServerSideProps` runs for each incoming request.

When to use `getServerSideProps`:
Use `getServerSideProps` when you need to fetch data and render the page on the server for every request. This is particularly useful for:
* Pages displaying real-time data (e.g., stock prices, news feeds).
* User-specific dashboards or profile pages that require authentication checks on the server.
* Pages where SEO is critical, and the content is highly dynamic.

Distinction from other Next.js rendering methods:
* Static Site Generation (SSG) with `getStaticProps`: Pages are pre-rendered at *build time* and can be cached by a CDN. Ideal for pages with static or infrequently updated content.
* Client-Side Rendering (CSR): The page content is rendered entirely in the browser after the initial HTML (often just a loading spinner) is loaded. Next.js still generates the initial empty HTML, and you would fetch data using `useEffect` or SWR on the client.

Example Code

// pages/products/[id].js or pages/dashboard.js
import React from 'react';

// This is the React component that will display the fetched data.
function ProductDetailPage({ product, error }) {
  if (error) {
    return <p>Error loading product: {error}</p>;
  }

  if (!product) {
    // This case shouldn't be hit with SSR if product is null and error is not set, 
    // but good for type safety or initial client-side render state if JS isn't ready.
    return <p>Loading product...</p>; 
  }

  return (
    <div>
      <h1>Product Name: {product.name}</h1>
      <p>Description: {product.description}</p>
      <p>Price: ${product.price}</p>
      <p>ID: {product.id}</p>
    </div>
  );
}

// getServerSideProps runs on the server for every request.
export async function getServerSideProps(context) {
  // For dynamic routes (e.g., pages/products/[id].js), context.params will contain route parameters.
  // For a non-dynamic page (e.g., pages/dashboard.js), context.params would be empty.
  const { id } = context.params || {}; // Destructure id, provide default empty object if context.params is undefined

  try {
    // Simulate fetching data from an external API
    // Replace 'https://api.example.com' with your actual API endpoint
    const apiUrl = `https://api.example.com/products/${id || 1}`; // Use '1' as a default ID if no 'id' param exists
    const res = await fetch(apiUrl);
    
    if (!res.ok) {
      // If the API response is not OK, throw an error with status and message
      const errorData = await res.json().catch(() => ({ message: 'Unknown error' }));
      throw new Error(`Failed to fetch product data (Status: ${res.status}, Message: ${errorData.message || res.statusText})`);
    }

    const product = await res.json();

    // The 'props' object returned will be passed to the component.
    return {
      props: {
        product,          // Data for the component
        error: null,       // No error occurred
      },
    };
  } catch (error) {
    console.error('Error in getServerSideProps:', error);
    // Return an error message to be displayed by the component
    return {
      props: {
        product: null,
        error: error.message || 'An unknown error occurred during data fetching',
      },
    };
  }
}

export default ProductDetailPage;