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: "" },
],
},
],
};
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
}
}
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);
};
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;
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>
);
}
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
}
}
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);
};
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" };
}
};
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)