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;