Skip to content

Commit

Permalink
feat: add intersection observer to homepage sections (#2361)
Browse files Browse the repository at this point in the history
  • Loading branch information
juanmahidalgo authored Feb 3, 2025
1 parent 74f906d commit cb8365a
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 19 deletions.
63 changes: 44 additions & 19 deletions webapp/src/components/HomePage/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo } from 'react'
import React, { useCallback, useMemo, useRef } from 'react'
import { useHistory } from 'react-router-dom'
import { Banner } from 'decentraland-dapps/dist/containers/Banner'
import { getAnalytics } from 'decentraland-dapps/dist/modules/analytics/utils'
Expand All @@ -19,6 +19,7 @@ import { NavigationTab } from '../Navigation/Navigation.types'
import { PageLayout } from '../PageLayout'
import { RankingsTable } from '../RankingsTable'
import { RecentlySoldTable } from '../RecentlySoldTable'
import { useIntersectionObserver } from './hooks'
import { Slideshow } from './Slideshow'
import { Props } from './HomePage.types'
import './HomePage.css'
Expand Down Expand Up @@ -162,31 +163,55 @@ const HomePage = (props: Props) => {
[sections, fetchAssetsForView]
)

useEffect(() => {
let view: HomepageView
for (view in homepage) {
fetchAssetsForView(view)
// Create a Map to store refs for each view section
const sectionRefs = useRef(new Map<HomepageView, HTMLDivElement>())

// Custom hook to handle intersection observer
const onIntersect = useCallback(
(view: HomepageView) => {
// Only fetch if we don't already have data for this view
const isLoadingView = homepageLoading[view]
if ((!homepage[view] || homepage[view].length === 0) && !isLoadingView) {
fetchAssetsForView(view)
}
},
[fetchAssetsForView, homepage, homepageLoading]
)

useIntersectionObserver({
refs: sectionRefs.current,
onIntersect,
options: {
rootMargin: '100px',
threshold: 0.1
}
// eslint-disable-next-line
}, [fetchAssetsForView])
})

const renderSlideshow = (view: HomepageView) => {
const hasItemsSection = view === View.HOME_NEW_ITEMS || view === View.HOME_WEARABLES

return (
<Slideshow
<div
ref={element => {
if (element) {
sectionRefs.current.set(view, element)
}
}}
key={view}
view={view}
title={t(`home_page.${view}`)}
subtitle={sectionsSubtitles[view]}
viewAllTitle={sectionsViewAllTitle[view]}
emptyMessage={sectionsEmptyMessages[view]}
assets={homepageLoading[view] ? [] : homepage[view]}
hasItemsSection={hasItemsSection}
isLoading={homepageLoading[view]}
onViewAll={() => handleViewAll(view)}
onChangeItemSection={hasItemsSection ? handleOnChangeItemSection : undefined}
/>
>
<Slideshow
view={view}
title={t(`home_page.${view}`)}
subtitle={sectionsSubtitles[view]}
viewAllTitle={sectionsViewAllTitle[view]}
emptyMessage={sectionsEmptyMessages[view]}
assets={homepageLoading[view] ? [] : homepage[view]}
hasItemsSection={hasItemsSection}
isLoading={homepageLoading[view]}
onViewAll={() => handleViewAll(view)}
onChangeItemSection={hasItemsSection ? handleOnChangeItemSection : undefined}
/>
</div>
)
}

Expand Down
43 changes: 43 additions & 0 deletions webapp/src/components/HomePage/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect } from 'react'
import { HomepageView } from '../../modules/ui/asset/homepage/types'

type IntersectionObserverProps = {
refs: Map<HomepageView, HTMLDivElement>
onIntersect: (view: HomepageView) => void
options?: IntersectionObserverInit
}

export const useIntersectionObserver = ({ refs, onIntersect, options = {} }: IntersectionObserverProps) => {
useEffect(() => {
// Keep track of which sections have been loaded
const loadedSections = new Set<HomepageView>()

const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
// Find which view this element corresponds to
const view = Array.from(refs.entries()).find(([_, element]) => element === entry.target)?.[0]

if (view && entry.isIntersecting && !loadedSections.has(view)) {
loadedSections.add(view)
onIntersect(view)
}
})
},
{
rootMargin: '100px',
threshold: 0.1,
...options
}
)

// Observe all section refs
refs.forEach(element => {
observer.observe(element)
})

return () => {
observer.disconnect()
}
}, [refs, onIntersect, options])
}

0 comments on commit cb8365a

Please sign in to comment.