Skip to content

Commit

Permalink
fix: Sentinel rendering and wrong PLP's pagination behavior (#2585)
Browse files Browse the repository at this point in the history
## What's the purpose of this pull request?

This PR intends to fix the `Sentinel` behavior by turn it a wrapper for
the `ProductGrid` component, also preventing the loop of requests
happening when the user load more pages (by clicking on the `Load more
products` button).

## How it works?

Currently, `Sentinel` is being rendered as a side `<div />` with the
`ProductGrid` component, disabling us to control the visibility of
viewport elements properly.

*Before*
**(The red line is the `Sentinel`)**

![Screenshot 2024-12-05 at 13 07
20](https://github.com/user-attachments/assets/9ce4ccdc-a68b-46c0-8da5-a04c4ab00af7)

With these changes, the `Sentinel` will wrap the `ProductGrid`, thus
having the same height, enabling the use of `threshold` option (see the
API options
[`here`](https://github.com/thebuilder/react-intersection-observer?tab=readme-ov-file#options))
to trigger the next page (and replace the `page` query parameter) only
when necessary.

*After*

![Screenshot 2024-12-05 at 13 34
49](https://github.com/user-attachments/assets/08b17b71-d80d-47d2-bc19-2ffce688d541)

## How to test it?

Test the `/office` page with different sizes to see if the loop of
requests still happens and if the `page` query parameter is still being
updated correctly.

### Starters Deploy Preview

vtex-sites/starter.store#630

## References

- Using the `useInView` hook:
https://github.com/thebuilder/react-intersection-observer
  • Loading branch information
lucasfp13 authored Dec 9, 2024
1 parent f3cbb15 commit ea59e77
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ProductCardProps } from '../ProductCard'
import { memo } from 'react'
import ViewportObserver from 'src/components/cms/ViewportObserver'
import { useOverrideComponents } from 'src/sdk/overrides/OverrideContext'
import useScreenResize from 'src/sdk/ui/useScreenResize'

interface Props {
/**
Expand Down Expand Up @@ -45,20 +46,20 @@ function ProductGrid({
} = {},
firstPage,
}: Props) {
const { isMobile } = useScreenResize()
const { __experimentalProductCard: ProductCard } =
useOverrideComponents<'ProductGallery'>()
const aspectRatio = 1

// TODO: Check if is also isMobile
const isFirstPage = firstPage === page
const aspectRatio = 1
const isGridWithViewportObserver = isMobile && firstPage === page

return (
<ProductGridSkeleton
aspectRatio={aspectRatio}
loading={products.length === 0}
>
<UIProductGrid>
{isFirstPage ? (
{isGridWithViewportObserver ? (
<>
{products.slice(0, 2).map(({ node: product }, idx) => (
<UIProductGridItem key={`${product.id}`}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,20 @@ function ProductGalleryPage({
const products = data?.search?.products?.edges ?? []

return (
<>
<Sentinel
products={products}
page={page}
pageSize={itemsPerPage}
title={title}
/>
<Sentinel
products={products}
page={page}
pageSize={itemsPerPage}
title={title}
>
<ProductGrid
products={products}
page={page}
pageSize={itemsPerPage}
productCard={productCard}
firstPage={firstPage}
/>
</>
</Sentinel>
)
}

Expand Down
24 changes: 15 additions & 9 deletions packages/core/src/sdk/search/Sentinel.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { useSearch } from '@faststore/sdk'
import { useEffect, useRef } from 'react'
import { useEffect, useRef, type PropsWithChildren } from 'react'
import { useInView } from 'react-intersection-observer'
import type { NextRouter } from 'next/router'
import { useRouter } from 'next/router'

import type { ProductSummary_ProductFragment } from '@generated/graphql'

import useScreenResize from 'src/sdk/ui/useScreenResize'
import { useViewItemListEvent } from '../analytics/hooks/useViewItemListEvent'

interface Props {
interface SentinelProps {
page: number
pageSize: number
title: string
Expand Down Expand Up @@ -38,19 +39,24 @@ const replacePagination = (page: string, router: NextRouter) => {
* Also, this component's name is kind of curious. Wikipedia calls is Page Break(https://en.wikipedia.org/wiki/Page_break)
* however all codes I've seen online use Sentinel
*/
function Sentinel({ page, pageSize, products, title }: Props) {
const viewedRef = useRef(false)
const { ref, inView } = useInView()
const { pages } = useSearch()

function Sentinel({
page,
pageSize,
products,
title,
children,
}: PropsWithChildren<SentinelProps>) {
const router = useRouter()

const { pages } = useSearch()
const { isMobile } = useScreenResize()
const { ref, inView } = useInView({ threshold: isMobile ? 0.3 : 0.7 })
const { sendViewItemListEvent } = useViewItemListEvent({
products,
title,
page,
pageSize,
})
const viewedRef = useRef(false)

useEffect(() => {
// Only replace pagination state when infinite scroll
Expand All @@ -72,7 +78,7 @@ function Sentinel({ page, pageSize, products, title }: Props) {
products.length,
])

return <div ref={ref} />
return <div ref={ref}>{children}</div>
}

export default Sentinel

0 comments on commit ea59e77

Please sign in to comment.