perf: Lazy loading for links in topic sections (#127)

This commit is contained in:
Anselm Eickhoff
2024-09-03 11:27:17 +01:00
committed by GitHub
parent c4d4afd4df
commit d2a3baa9a2
7 changed files with 74 additions and 33 deletions

View File

@@ -1,6 +1,8 @@
import React from "react"
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { LinkItem } from "./link-item"
import { LaAccount, PersonalLinkLists, Section as SectionSchema, Topic, UserRoot } from "@/lib/schema"
import { Skeleton } from "@/components/ui/skeleton"
import { Loader2 } from "lucide-react"
interface SectionProps {
topic: Topic
@@ -27,6 +29,12 @@ export function Section({
me,
personalLinks
}: SectionProps) {
const [nLinksToLoad, setNLinksToLoad] = useState(10);
const linksToLoad = useMemo(() => {
return section.links?.slice(0, nLinksToLoad)
}, [section.links, nLinksToLoad])
return (
<div className="flex flex-col">
<div className="flex items-center gap-4 px-6 py-2 max-lg:px-4">
@@ -35,9 +43,9 @@ export function Section({
</div>
<div className="flex flex-col gap-px py-2">
{section.links?.map(
{linksToLoad?.map(
(link, index) =>
link?.url && (
link?.url ? (
<LinkItem
key={index}
topic={topic}
@@ -51,9 +59,52 @@ export function Section({
me={me}
personalLinks={personalLinks}
/>
) : (
<Skeleton key={index} className="h-14 xl:h-11 w-full" />
)
)}
{section.links?.length && section.links?.length > nLinksToLoad && (
<LoadMoreSpinner onLoadMore={() => setNLinksToLoad(n => n + 10)} />
)}
</div>
</div>
)
}
const LoadMoreSpinner = ({ onLoadMore }: { onLoadMore: () => void }) => {
const spinnerRef = useRef<HTMLDivElement>(null)
const handleIntersection = useCallback(
(entries: IntersectionObserverEntry[]) => {
const [entry] = entries
if (entry.isIntersecting) {
onLoadMore()
}
},
[onLoadMore]
)
useEffect(() => {
const observer = new IntersectionObserver(handleIntersection, {
root: null,
rootMargin: "0px",
threshold: 1.0,
})
if (spinnerRef.current) {
observer.observe(spinnerRef.current)
}
return () => {
if (spinnerRef.current) {
observer.unobserve(spinnerRef.current)
}
}
}, [handleIntersection])
return (
<div ref={spinnerRef} className="flex justify-center py-4">
<Loader2 className="h-6 w-6 animate-spin" />
</div>
)
}