Add a Component That Fetches Data

Extend a Storefront Next page to fetch data on the server and pass it to a React component. This guide builds on Add a Page and a Component by adding a server-side loader that retrieves products from B2C Commerce and renders them in a new component.

Prerequisites

Steps

  1. Create a FeaturedProducts component that renders a grid of products.

    a. In {project-folder}/src/components, create a folder named featured-products.

    b. In the new featured-products folder, create index.tsx with this code.

    import { type ReactElement } from 'react';
    
    export interface Product {
        productId: string;
        productName: string;
        priceMax?: number;
        image?: { link: string; alt: string };
    }
    
    export interface FeaturedProductsProps {
        products: Product[];
        title?: string;
    }
    
    export default function FeaturedProducts({ products, title = 'Featured Products' }: FeaturedProductsProps): ReactElement {
        return (
            <section className="container mx-auto px-4 py-8">
                <h2 className="text-2xl font-bold mb-6">{title}</h2>
                <ul className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
                    {products.map((product) => (
                        <li key={product.productId} className="border rounded-lg p-4">
                            {product.image && (
                                <img
                                    src={product.image.link}
                                    alt={product.image.alt}
                                    className="w-full aspect-square object-cover rounded mb-2"
                                />
                            )}
                            <p className="font-medium text-sm">{product.productName}</p>
                            {product.priceMax && (
                                <p className="text-muted-foreground text-sm">${product.priceMax.toFixed(2)}</p>
                            )}
                        </li>
                    ))}
                </ul>
            </section>
        );
    }
    

    FeaturedProducts accepts a products array and an optional title. It renders a responsive grid of product cards, each showing the product image, name, and price.

  2. Add a loader to the custom page route to fetch products from B2C Commerce. Open {project-folder}/src/routes/_app.custom-page.tsx and replace its contents with this code.

    import { type ReactElement } from 'react';
    import { type LoaderFunctionArgs } from 'react-router';
    import { createPage, type RouteComponentProps } from '@/components/create-page';
    import CustomBanner from '@/components/custom-banner';
    import FeaturedProducts, { type Product } from '@/components/featured-products';
    import { createApiClients } from '@/lib/api-clients.server';
    
    export async function loader({ context }: LoaderFunctionArgs) {
        const clients = createApiClients(context);
        const { data } = await clients.shopperSearch.productSearch({
            params: {
                query: {
                    q: 'dress',
                    limit: 4,
                    allImages: true,
                },
            },
        });
        const products: Product[] = (data.hits ?? []).map((hit) => ({
            productId: hit.productId,
            productName: hit.productName ?? '',
            priceMax: hit.priceMax,
            image: hit.image
                ? { link: hit.image.link, alt: hit.image.alt ?? hit.productName ?? '' }
                : undefined,
        }));
        return { products };
    }
    
    export type CustomPageData = Awaited<ReturnType<typeof loader>>;
    
    function CustomPageView({ loaderData }: RouteComponentProps<CustomPageData>): ReactElement {
        return (
            <div className="pb-16">
                <CustomBanner title="Welcome to the Custom Collection!" />
                <FeaturedProducts products={loaderData.products} />
            </div>
        );
    }
    
    export default createPage<CustomPageData>({
        component: CustomPageView,
    });
    

    The loader function runs on the server before the page renders. createApiClients(context) returns all Shopper API clients configured for the current site. The createApiClients function is a template wrapper around the framework's createCommerceApiClients function. createApiClients reads site configuration, credentials, and locale from context and sets up authentication automatically so you don't need to pass those values manually. The loader calls the Shopper Search API to retrieve four products matching the query dress and destructures data from the response. The results are mapped to the Product type and returned as loaderData. CustomPageView receives loaderData as a prop and passes the products to FeaturedProducts. CustomPageData is derived directly from the loader's return type, so the component stays in sync with the data shape automatically.

  3. In a terminal window, go to the storefront folder.

    cd {project-folder}
    
  4. Build the storefront and run the development server.

    pnpm run build
    pnpm run dev
    
  5. Navigate to http://localhost:5173/custom-page. The page now shows the banner followed by a grid of products fetched from B2C Commerce.

Custom page shows the featured products that are fetched with the Shopper API

Next Steps

See Also