| setQuery(prev => ({ ...prev, tagIDs })) | setQuery(prev => ({ ...prev, tagIDs })) | ||||
| }, [setQuery]) | }, [setQuery]) | ||||
| const { data, isLoading, setSize, mutate } = useSWRInfinite( | |||||
| const { data, isLoading, error, setSize, mutate } = useSWRInfinite( | |||||
| (pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, isCreatedByMe, tagIDs, searchKeywords), | (pageIndex: number, previousPageData: AppListResponse) => getKey(pageIndex, previousPageData, activeTab, isCreatedByMe, tagIDs, searchKeywords), | ||||
| fetchAppList, | fetchAppList, | ||||
| { revalidateFirstPage: true }, | |||||
| { | |||||
| revalidateFirstPage: true, | |||||
| shouldRetryOnError: false, | |||||
| dedupingInterval: 500, | |||||
| errorRetryCount: 3, | |||||
| }, | |||||
| ) | ) | ||||
| const anchorRef = useRef<HTMLDivElement>(null) | const anchorRef = useRef<HTMLDivElement>(null) | ||||
| useEffect(() => { | useEffect(() => { | ||||
| const hasMore = data?.at(-1)?.has_more ?? true | const hasMore = data?.at(-1)?.has_more ?? true | ||||
| let observer: IntersectionObserver | undefined | let observer: IntersectionObserver | undefined | ||||
| if (error) { | |||||
| if (observer) | |||||
| observer.disconnect() | |||||
| return | |||||
| } | |||||
| if (anchorRef.current) { | if (anchorRef.current) { | ||||
| observer = new IntersectionObserver((entries) => { | observer = new IntersectionObserver((entries) => { | ||||
| if (entries[0].isIntersecting && !isLoading && hasMore) | |||||
| if (entries[0].isIntersecting && !isLoading && !error && hasMore) | |||||
| setSize((size: number) => size + 1) | setSize((size: number) => size + 1) | ||||
| }, { rootMargin: '100px' }) | }, { rootMargin: '100px' }) | ||||
| observer.observe(anchorRef.current) | observer.observe(anchorRef.current) | ||||
| } | } | ||||
| return () => observer?.disconnect() | return () => observer?.disconnect() | ||||
| }, [isLoading, setSize, anchorRef, mutate, data]) | |||||
| }, [isLoading, setSize, anchorRef, mutate, data, error]) | |||||
| const { run: handleSearch } = useDebounceFn(() => { | const { run: handleSearch } = useDebounceFn(() => { | ||||
| setSearchKeywords(keywords) | setSearchKeywords(keywords) |