feat(island): allow lazy load blog card list with intersection observer

This commit is contained in:
Julien Oculi 2024-07-10 13:48:47 +02:00
parent 3dd4f2cc21
commit 8b716a382f

View file

@ -2,8 +2,8 @@ import { BlogCard, BlogProps } from ':components/BlogBlocks.tsx'
import Suspense from ':islands/Suspens.tsx' import Suspense from ':islands/Suspens.tsx'
import { requestApiStream } from ':src/utils.ts' import { requestApiStream } from ':src/utils.ts'
import { Signal, useSignal } from '@preact/signals' import { Signal, useSignal } from '@preact/signals'
import type { JSX } from 'preact' import type { JSX, Ref } from 'preact'
import { useEffect } from 'preact/hooks' import { useEffect, useRef } from 'preact/hooks'
function fillList( function fillList(
list: Signal<JSX.Element[]>, list: Signal<JSX.Element[]>,
@ -27,13 +27,31 @@ function fillList(
} }
export default function BlogCardList( export default function BlogCardList(
{ limit, usePlaceholder }: { usePlaceholder?: boolean; limit?: number }, { limit, usePlaceholder, useObserver }: {
usePlaceholder?: boolean
limit?: number
useObserver?: boolean
},
) { ) {
const list = useSignal<JSX.Element[]>([]) const list: Signal<JSX.Element[]> = useSignal<JSX.Element[]>([])
const ac = new AbortController() const ac = new AbortController()
const ref = useRef(null)
useEffect(() => { useEffect(() => {
if (ref.current && useObserver) {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
fillList(list, { limit, ac }) fillList(list, { limit, ac })
observer.disconnect()
}
}, {
rootMargin: '300px',
})
//@ts-expect-error Need to investigate why it's work
observer.observe(ref.current.base)
} else {
fillList(list, { limit, ac })
}
}) })
if (limit && usePlaceholder) { if (limit && usePlaceholder) {
@ -41,7 +59,7 @@ export default function BlogCardList(
.from({ length: limit }) .from({ length: limit })
.map((_, index) => ( .map((_, index) => (
<Suspense <Suspense
loader={<Placeholder />} loader={<Placeholder ref={index === 0 ? ref : undefined} />}
fallback={Fallback} fallback={Fallback}
signal={ac.signal} signal={ac.signal}
> >
@ -54,9 +72,12 @@ export default function BlogCardList(
return <>{list}</> return <>{list}</>
} }
function Placeholder() { function Placeholder({ ref }: { ref?: Ref<HTMLDivElement> | undefined }) {
return ( return (
<div class='components__blog_block components__blog_block--card components__blog_block--placeholder'> <div
class='components__blog_block components__blog_block--card components__blog_block--placeholder'
ref={ref}
>
<h3>Chargement ...</h3> <h3>Chargement ...</h3>
</div> </div>
) )