DEV Community

Zaid Rehman
Zaid Rehman

Posted on

Server-Side Rendering in Sections

Introduction:

Welcome to the fourth tutorial in the Fynd Platform Theme Development series. In this session, we will focus on implementing server-side rendering (SSR) for sections using the serverFetch function. We’ll utilize a detailed GraphQL query to fetch product data dynamically and integrate it into the section using useGlobalStore. By the end of this tutorial, you’ll understand how to fetch data server-side and pre-render sections for enhanced performance and SEO.

1. What Is Server-Side Rendering?

Server-side rendering (SSR) ensures that web page content is rendered on the server before being sent to the client. Key benefits include:

  • Improved initial page load speed.
  • Enhanced SEO due to pre-rendered content.
  • Preloaded dynamic data before JavaScript execution on the client.

In Fynd themes, the serverFetch function facilitates fetching and passing data to sections during SSR.

2. Anatomy of a Section with severFetch

Sections are modular and reusable building blocks of a Fynd theme. A section consists of the following parts:

  • Component: Defines the React component responsible for rendering the section.
  • serverFetch (Optional): Fetches data during server-side rendering.
  • settings: Configures the section with customizable properties and blocks.
  • blocks (Optional): Represents nested, reusable content units.

Example Section Structure:

export function Component({ props = {}, blocks = [] }) {
  return <div>{props.title}</div>;
}

Component.serverFetch = async ({ fpi, router }) => {
  const slug = router?.params?.slug;
  const query = `
    query($slug: String!) {
      product(slug: $slug) {
        name
      }
    }
  `;
  return fpi.executeGQL(query, { slug });
};

export const settings = {
  label: "Example Section",
  props: [
    { id: "title", label: "Title", type: "text", default: "Default Title" },
  ],
  blocks: [
    {
      label: "Example Block",
      type: "text",
      props: [
        { id: "content", label: "Content", type: "text", default: "" },
      ],
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode

3. GraphQL Query for Product Data

Here’s the GraphQL query we’ll use to fetch product details:

query($slug: String!) {
  product(slug: $slug) {
    name
    description
    price {
      effective {
        currency_symbol
        min
      }
      marked {
        currency_symbol
        min
      }
    }
    media {
      url
      alt
    }
    brand {
      name
      logo {
        url
        alt
      }
    }
    categories {
      name
    }
    variants {
      key
      items {
        name
        slug
      }
    }
    short_description
  }
}
Enter fullscreen mode Exit fullscreen mode

This query retrieves product details, including name, price, images, and metadata.

4. Implementing serverFetch

Define serverFetch

The serverFetch function executes the GraphQL query to fetch product data by slug:

Component.serverFetch = async ({ fpi, router }) => {
  const slug = router?.params?.slug; // Fetch slug from the router
  const query = `
    query($slug: String!) {
      product(slug: $slug) {
        name
        description
        price {
          effective {
            currency_symbol
            min
          }
          marked {
            currency_symbol
            min
          }
        }
        media {
          url
          alt
        }
        brand {
          name
          logo {
            url
            alt
          }
        }
        categories {
          name
        }
        variants {
          key
          items {
            name
            slug
          }
        }
        short_description
      }
    }
  `;

  const variables = { slug };

  return fpi.executeGQL(query, variables);
};
Enter fullscreen mode Exit fullscreen mode

5. Accessing Product Data Using useGlobalStore

Retrieve Data
Use the useGlobalStore hook to fetch the data provided by serverFetch:

import { useGlobalStore } from "fdk-core/utils";

const productDetails = useGlobalStore(fpi.getters.PRODUCT);
const { product_details: { uid }, product_meta, product_price_by_slug } = productDetails;
Enter fullscreen mode Exit fullscreen mode

Render the Component
Render the section with the fetched product details:

import { useGlobalStore } from "fdk-core/utils";

export function Component() {
  const productDetails = useGlobalStore(fpi.getters.PRODUCT);
  const { product_details: { uid, name, description, short_description }, product_price_by_slug } = productDetails;

  if (!productDetails) return <div>Loading...</div>;

  return (
    <div>
      <h1>{name}</h1>
      <p>{short_description}</p>
      <p>{description}</p>
      <p>
        Effective Price: {product_price_by_slug.price.effective.currency_symbol}
        {product_price_by_slug.price.effective.min}
      </p>
      <p>
        Marked Price: {product_price_by_slug.price.marked.currency_symbol}
        {product_price_by_slug.price.marked.min}
      </p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. Advanced Use Cases

Fetching Multiple Data Points
Extend the GraphQL query to fetch additional data, such as promotions and coupons:

promotions(slug: $slug, pageSize: 30) {
  available_promotions {
    promotion_name
    offer_text
  }
}
coupons {
  available_coupon_list {
    title
    coupon_code
    coupon_value
  }
}
Enter fullscreen mode Exit fullscreen mode

Update the serverFetch function:

Component.serverFetch = async ({ fpi, router }) => {
  const slug = router?.params?.slug;
  const query = `
    query($slug: String!) {
      product(slug: $slug) {
        name
        ...
      }
      promotions(slug: $slug, pageSize: 30) {
        available_promotions {
          promotion_name
          offer_text
        }
      }
      coupons {
        available_coupon_list {
          title
          coupon_code
          coupon_value
        }
      }
    }
  `;

  const variables = { slug };
  return fpi.executeGQL(query, variables);
};
Enter fullscreen mode Exit fullscreen mode

Error Handling
Add error handling for robustness:

Component.serverFetch = async ({ fpi, router }) => {
  try {
    const slug = router?.params?.slug;
    const query = `
      query($slug: String!) { ... }
    `;
    return await fpi.executeGQL(query, { slug });
  } catch (error) {
    console.error("Error fetching data:", error);
    return { error: "Failed to fetch data" };
  }
};

Enter fullscreen mode Exit fullscreen mode

7. Best Practices for serverFetch

  • Optimize Queries: Fetch only required fields to minimize payload size.
  • Use useGlobalStore Effectively: Leverage getters for seamless integration with the Redux store.
  • Handle Errors Gracefully: Display fallback data or error messages for missing content.
  • Cache Responses: Use caching to reduce redundant API calls.
  • Test Thoroughly: Validate serverFetch in local, staging, and production environments.

Conclusion:

With serverFetch and useGlobalStore, you can efficiently fetch, store, and render server-side data for sections. This approach enhances both performance and SEO, making your themes more robust and user-friendly.

In the next tutorial, we’ll explore global configurations to manage theme-wide settings. Stay tuned!

Top comments (0)