84 lines
2.8 KiB
JavaScript
84 lines
2.8 KiB
JavaScript
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
|
export default function useLazyProfileFavourites({ username, initialFavourites, enabled }) {
|
|
const hasInitialValue = initialFavourites !== null && initialFavourites !== undefined
|
|
const initialItems = Array.isArray(initialFavourites)
|
|
? initialFavourites
|
|
: (initialFavourites?.data ?? [])
|
|
const [items, setItems] = useState(() => initialItems)
|
|
const [nextCursor, setNextCursor] = useState(() => initialFavourites?.next_cursor ?? null)
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState(false)
|
|
const requestKeyRef = useRef(username)
|
|
const requestedRef = useRef(hasInitialValue)
|
|
const abortRef = useRef(null)
|
|
|
|
useEffect(() => {
|
|
if (requestKeyRef.current === username) return undefined
|
|
|
|
abortRef.current?.abort()
|
|
abortRef.current = null
|
|
requestKeyRef.current = username
|
|
requestedRef.current = false
|
|
setItems([])
|
|
setNextCursor(null)
|
|
setLoading(false)
|
|
setError(false)
|
|
return undefined
|
|
}, [username])
|
|
|
|
useEffect(() => {
|
|
if (requestKeyRef.current !== username || !hasInitialValue) return undefined
|
|
|
|
abortRef.current?.abort()
|
|
abortRef.current = null
|
|
requestedRef.current = true
|
|
setItems(initialItems)
|
|
setNextCursor(initialFavourites?.next_cursor ?? null)
|
|
setLoading(false)
|
|
setError(false)
|
|
return undefined
|
|
}, [hasInitialValue, initialFavourites, initialItems, username])
|
|
|
|
const load = useCallback(async () => {
|
|
if (!enabled || hasInitialValue || requestedRef.current || !username) return
|
|
|
|
requestedRef.current = true
|
|
const controller = new AbortController()
|
|
const requestKey = requestKeyRef.current
|
|
abortRef.current = controller
|
|
setLoading(true)
|
|
setError(false)
|
|
|
|
try {
|
|
const response = await fetch(`/api/profile/${encodeURIComponent(username)}/favourites`, {
|
|
headers: { Accept: 'application/json' },
|
|
credentials: 'same-origin',
|
|
signal: controller.signal,
|
|
})
|
|
if (!response.ok) throw new Error('Favourites could not be loaded.')
|
|
const payload = await response.json()
|
|
if (requestKey !== requestKeyRef.current || controller.signal.aborted) return
|
|
setItems(Array.isArray(payload?.data) ? payload.data : [])
|
|
setNextCursor(payload?.next_cursor ?? null)
|
|
} catch (caught) {
|
|
if (caught?.name === 'AbortError' || requestKey !== requestKeyRef.current) return
|
|
requestedRef.current = false
|
|
setError(true)
|
|
} finally {
|
|
if (requestKey === requestKeyRef.current) {
|
|
abortRef.current = null
|
|
setLoading(false)
|
|
}
|
|
}
|
|
}, [enabled, hasInitialValue, username])
|
|
|
|
useEffect(() => {
|
|
if (enabled) load()
|
|
}, [enabled, load])
|
|
|
|
useEffect(() => () => abortRef.current?.abort(), [])
|
|
|
|
return { items, nextCursor, loading, error, retry: load }
|
|
}
|