Hydrogen Pagination component only adds products to a list instead of returning next page

Hydrogen Pagination component only adds products to a list instead of returning next page

levinriegner
Shopify Partner
3 0 1

Hi everyone,

I am trying to set up pagination using the Hydrogen Pagination component. I have set everything just like the documentation suggests. However, when using the injected NextLink component, the pagination always just adds the new products to the existing page (almost like infinite scroll behavior) instead of moving to the next page.

 

I checked the results of getPaginationVariables and they look good to me. It returns both the first value as well as a changing endCursor.

 

EDIT: I tested the query in the GraphQL explorer and it works properly.
EDIT 2: If I manually remove the "%3D%3D" (==) from the cursor in the URL, then reload the page, I get the expected results.

EDIT 3: Inching close. It seems like for some reason as second "=" is added to the URL which breaks the pagination.
EDIT 4: Except it only breaks it on the site, not the GraphQl explorer...
EDIT 5: If I log the products going into the Pagination component I see only the products for the current page. If I log the nodes inside of the component I see even the previous pages. Not sure whats going on here.

I am sharing my current implementation for reference. I'm quite stuck here. Let me know if you notice any issues.

The pagination component

<Pagination connection={products}>
      {({nodes, PreviousLink, NextLink}) => (
        <>
          <div className={className}>
            <div className={styles.titleContainer}>
              <div>{title && <h2 className="serif">{title}</h2>}</div>
              <div className={styles.titleButtonContainer}>
                <PreviousLink className={styles.button}>
                  <ArrowIcon direction="left" />
                </PreviousLink>

                <NextLink className={styles.button}>
                  <ArrowIcon direction="right" />
                </NextLink>
              </div>
            </div>

            <div className={styles.scrollBarHideContainer}>
              <div className={styles.productContainer}>
                <div className={styles.containerInner}>
                  {nodes.map((product: any) => (
                    <div key={product.id} className={styles.productWrapper}>
                      <ProductsViewItem key={product.id} product={product} />
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </div>
        </>
      )}
    </Pagination>


The loader of the parent

export async function loader({request, context}: LoaderArgs) {
  const url = new URL(request.url);
  const searchParams = new URLSearchParams(url.search);
  const searchTerm = String(searchParams.get('q') || '');

  if (!searchTerm) {
    return {
      searchResults: {results: null, totalResults: 0},
      searchTerm,
    };
  }

  const searchPaginationVariables = getPaginationVariables(request, {
    pageBy: 8,
  });
  console.log(request)
  const popularProductsPaginationVariables = getPaginationVariables(request, {
    pageBy: 2,
  });

  const [searchRes, bestSellingProductsRes] = await Promise.all([
    context.storefront.query(SEARCH_QUERY, {
      variables: {
        query: searchTerm,
        ...searchPaginationVariables,
      },
    }),
    context.storefront.query(ALL_PRODUCTS_QUERY, {
      variables: {
        ...popularProductsPaginationVariables,
        sortKey: 'BEST_SELLING',
      },
    }),
  ]);


The Graph query

export const PRODUCT_ITEM_FRAGMENT = `#graphql
  fragment MoneyProductItem on MoneyV2 {
    amount
    currencyCode
  }
  fragment ProductItem on Product {
    id
    handle
    title
    vendor
    createdAt
    featuredImage {
      id
      altText
      url
      width
      height
    }
    priceRange {
      minVariantPrice {
        ...MoneyProductItem
      }
      maxVariantPrice {
        ...MoneyProductItem
      }
    }
    variants(first: 1) {
      nodes {
        selectedOptions {
          name
          value
        }
      }
    }
    collections(first: 1) {
      edges {
        node {
          id
          handle
          title
        }
      }
    }
  }
` as const;

export const ALL_PRODUCTS_QUERY = `#graphql
  query AllProducts(
    $first: Int
    $last: Int
    $startCursor: String
    $endCursor: String
    $query: String,
    $sortKey: ProductSortKeys,
    $reverse: Boolean = false
  ) {
    products(
      first: $first, 
      last: $last, 
      before: $startCursor, 
      after: $endCursor
      query: $query,
      sortKey: $sortKey,
      reverse: $reverse,
    ) {
      nodes {
        ...ProductItem
      }
      pageInfo {
        hasPreviousPage
        hasNextPage
        startCursor
        endCursor
      }
    }
  }
  ${PRODUCT_ITEM_FRAGMENT}
` as const;




Replies 2 (2)

Liam
Shopify Staff
2873 312 821

Hi Levinriegner,

 

It seems like you are on the right track and have done quite a bit of debugging already. One possible issue could be the way your cursors are being handled While GraphQL uses cursors for pagination, the cursor values are usually base64 encoded.

 

The extra "=" character you are seeing could be due to this encoding. When you manually remove the "%3D%3D" (which is URL-encoded "==") from the URL and reload the page, and it works as expected, it suggests that the cursor is not being decoded correctly when it is used for the next page query.

 

You can try to decode the cursor before using it in your query. If you are using JavaScript, you can use the atob() function to decode a base64 string.

 

Try this out and let us know if you're still having issues.

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

levinriegner
Shopify Partner
3 0 1

Hi Liam, 

 

Thank your very much for your reply!

For time reasons I went with a workaround. I am now mapping the products inside the Pagination component using the original query response instead of the nodes returned by the component. I am also using the hasPreviousPage etc. utilities which strangely do work properly without any other modifications.

I'd be surprised if there were an issue with the encoding since the utilities do work as expected. But if I have some time I will give it a try and report back!