diff --git a/src/hooks/useRepoRootTree.ts b/src/hooks/useRepoRootTree.ts index f5c8aee..e201efc 100644 --- a/src/hooks/useRepoRootTree.ts +++ b/src/hooks/useRepoRootTree.ts @@ -1,67 +1,17 @@ -import type { $output as RepoTreeResponse } from '@atcute/tangled/types/repo/tree' -import { useEffect, useRef, useState } from 'react' +import { useCallback } from 'react' import type { Repo } from '../lib/tangled' import { getRepoTree } from '../lib/tangled/repo' - -type RootTreeState = { - error?: Error - key: string - tree?: RepoTreeResponse -} +import { useDeferredResource } from './useDeferredResource' export function useRepoRootTree(repo: Repo | null, isEnabled: boolean) { - const cache = useRef(new Map()) - const requests = useRef(new Map>()) - const [state, setState] = useState(null) - const repoKey = repo?.uri ?? null - - useEffect(() => { - if (repo === null || !isEnabled) return - - const cachedTree = cache.current.get(repo.uri) - if (cachedTree !== undefined) { - setState({ key: repo.uri, tree: cachedTree }) - return - } - - let isCancelled = false - setState({ key: repo.uri }) - - const request = getRootTree(repo, requests.current) - void request - .then((tree) => { - cache.current.set(repo.uri, tree) - if (!isCancelled) setState({ key: repo.uri, tree }) - }) - .catch((caught) => { - if (!isCancelled) { - setState({ - key: repo.uri, - error: - caught instanceof Error ? caught : new Error('Unable to load repository contents'), - }) - } - }) + const loadRootTree = useCallback(async () => { + if (repo === null) throw new Error('Repository is required to load its root tree') - return () => { - isCancelled = true - } - }, [isEnabled, repo]) - - const isCurrentRepository = state?.key === repoKey - return { - error: isCurrentRepository ? (state.error ?? null) : null, - rootTree: isCurrentRepository ? (state.tree ?? null) : null, - } -} - -function getRootTree(repo: Repo, requests: Map>) { - const existingRequest = requests.get(repo.uri) - if (existingRequest !== undefined) return existingRequest - - const request = getRepoTree(repo).finally(() => { - requests.delete(repo.uri) + return getRepoTree(repo) + }, [repo]) + const { data, error } = useDeferredResource(repo?.uri ?? null, isEnabled, loadRootTree, { + cache: true, }) - requests.set(repo.uri, request) - return request + + return { error, rootTree: data } }