Building the Product List Page

Overview

The Product List Page (PLP) is the page that displays a list of products to your end users. This guide will explore how to build a PLP using the Merchstack API.

Before we get started, we are assuming that you have already set up your project to access the Merchstack API. If you have not, please refer to the Accessing the API section of the documentation.

Product Listing Page

The following is a step-by-step guide to creating a basic product listing page using the Merchstack API.

Step 1: Create a Product Listing Component

The first step is to create a component that will be responsible for displaying the products. This component will be responsible for making the API call to Merchstack and displaying the results. Create a new file called ProductListing.jsx and add the following code:

import React from 'react'
import { useQuery, gql } from '@apollo/client'

const GET_PRODUCTS = gql`
  query AlternativeSearch($input: AlternativeSearchInput!) {
    alternativeSearch(input: $input) {
        items {
          name
          slug
          brand
          variants {
            name
            sku
            stockLevel
            asset {
              preview
            }
            lineage
            id
          }
          price {
            ...on PriceRange {
              min
              max
            }
          }
          compareAtPrice {
            ...on PriceRange {
              min
              max
            }
          }
          id
          lineage
          code
          stockLevel
          score
          asset {
            id
            preview
          }
          slug
          categoryIds
        }
        totalItems
      }
  }
`

function ProductListing() {
  const { loading, error, data } = useQuery(GET_PRODUCTS, {
    variables: {
      input: {
        inStock: true,
        take: 10,
        skip: 0,
      },
    },
  })
  
  if (loading) return <p>Loading...</p>
  if (error) return <p>Error :(</p>

  return data.alternativeSearch.items.map(({ id, name }) => (
    <div key={id}>
      <p>{name}</p>
    </div>
  ))
}

export default ProductListing

In the above code, we are using the useQuery hook to make a call to the Merchstack API. We are using the alternativeSearch query to retrieve a list of products. The alternativeSearch query is a powerful query that allows you to search for products based on a variety of criteria.

The alternativeSearch query returns a list of products. For each product, we are displaying the name of the product. You can display any of the other fields that are returned by the alternativeSearch query.

You can modify the component to display the products in any way you please. For example, you could display the products in a grid, table or a list. You could also add pagination to the component to allow the user to navigate through the list of products.

Although, you have the liberty to display the products in any way you please, we have created a sample product card/tile component that you can use to display the products. You can find the component by visiting Product Tile/Card file. You can import the component and use it in your ProductListing component.

You can handle pagination using the skip and take arguments of the alternativeSearch query. We also return the totalItems field from the alternativeSearch query helpful for pagination. Below is the sample code for pagination with page numbers, next, previous, first and last buttons.

import React, { useState } from 'react'
import { useQuery, gql } from '@apollo/client'

const GET_PRODUCTS = gql`
  query AlternativeSearch($input: AlternativeSearchInput!) {
    alternativeSearch(input: $input) {
        items {
          name
          slug
          brand
          variants {
            name
            sku
            stockLevel
            asset {
              preview
            }
            lineage
            id
          }
          price {
            ...on PriceRange {
              min
              max
            }
          }
          compareAtPrice {
            ...on PriceRange {
              min
              max
            }
          }
          id
          lineage
          code
          stockLevel
          score
          asset {
            id
            preview
          }
          slug
          categoryIds
        }
        totalItems
      }
  }
`

function ProductListing() {
  const [skip, setSkip] = useState(0)
  const [take, setTake] = useState(10)
  const { loading, error, data } = useQuery(GET_PRODUCTS, {
    variables: {
      input: {
        inStock: true,
        take,
        skip,
      },
    },
  })

  if (loading) return <p>Loading...</p>
  if (error) return <p>Error :(</p>

  return (
    <>
      {data.alternativeSearch.items.map(({ id, name }) => (
        <div key={id}>
          <p>{name}</p>
        </div>
      ))}

      <div className="flex justify-center items-center">
        <button
          className="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-4 rounded-l"
          onClick={() => {
            setSkip(0)
          }
        }>
          First
        </button>
        <button
          className="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-4 rounded-l"
          onClick={() => {
            if (skip > 0) {
              setSkip(skip - take)
            }
          }}
        >
          Previous
        </button>
        
        <p className="mr-4">Page {skip / take + 1}</p>
        
        <button
          className="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-4 rounded-r"
          onClick={() => {
            if (skip + take < data.alternativeSearch.totalItems) {
              setSkip(skip + take)
            }
          }}
        >
          Next
        </button>

        <button
          className="bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-2 px-4 rounded-r"
          onClick={() => {
            setSkip(data.alternativeSearch.totalItems - take)
          }}
        >
          Last
        </button>
      </div>
    </>
  )
}

export default ProductListing

Step 2 (optional): Add the Product Listing Component to a Page

The next step is to add the ProductListing component to a page. Create a new file called ProductListingPage.jsx and add the following code:

import React from 'react'
import ProductListing from './ProductListing'

function ProductListingPage() {
  return (
    <div>
      <ProductListing />
    </div>
  )
}

export default ProductListingPage

In the above code, we are simply rendering the ProductListing component. You can pass the desired options to the alternativeSearch query as props to the ProductListing component. For example, if you wanted to display 20 products instead of 10, you could pass the take prop to the ProductListing component. The idea is to make the ProductListing component as flexible as possible so that it can be used in a variety of different scenarios.

This is an optional step. You can skip this step and create or import the ProductListing component to your components/containers/page directly if you prefer.

Step 3 (optional): Add the Product Listing Page to the Router

The final step is to add the ProductListingPage component to the router. Open the App.jsx file and add the following code:

import React from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import ProductListingPage from './ProductListingPage'

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/">
          <ProductListingPage />
        </Route>
      </Switch>
    </Router>
  )
}

export default App

In the above code, we are adding the ProductListingPage component to the router. Now when you navigate to the root of your application, you should see a list of products.

This is an optional step. You can skip this step and hook to the application router as per your preference.

More Information on Alternate Search

The alternativeSearch query is a powerful query that allows you to search for products based on a variety of criteria. For more information on the alternativeSearch query or any other queries, please refer to the GraphQL Playground -> Docs -> alternativeSearch

We will keep referring to the alternativeSearch query throughout the storefront integration documentation. It is important to understand how to use this query. We recommend that you spend some time familiarizing yourself with the query.

Resources

Concepts

Learn about the concepts in the Merchstack platform.

Integrations

Learn about the ins and outs of building a custom integration.

Guides

Follow our useful guides to get up and running quickly.

Getting Help

Learn who to reach out to if you get stuck and need more assistance.