diff --git a/src/components/FileExplorer/hooks/useVisibleNodesGenerator.tsx b/src/components/FileExplorer/hooks/useVisibleNodesGenerator.tsx index 35610f5..56b2666 100644 --- a/src/components/FileExplorer/hooks/useVisibleNodesGenerator.tsx +++ b/src/components/FileExplorer/hooks/useVisibleNodesGenerator.tsx @@ -1,9 +1,9 @@ import { useConfigs } from 'containers/ConfigsContext' import { platform } from 'platforms' import { useCallback, useState } from 'react' +import { useAbortableEffect } from 'utils/hooks/useAbortableEffect' import { useCatchNetworkError } from 'utils/hooks/useCatchNetworkError' import { useLoadedContext } from 'utils/hooks/useLoadedContext' -import { useSequentialEffect } from 'utils/hooks/useSequentialEffect' import { VisibleNodesGenerator } from 'utils/VisibleNodesGenerator' import { SideBarStateContext } from '../../../containers/SideBarState' @@ -17,12 +17,12 @@ export function useVisibleNodesGenerator(metaData: MetaData | null) { const setStateContext = useLoadedContext(SideBarStateContext).onChange // Only run when metadata or accessToken changes - useSequentialEffect( + useAbortableEffect( useCallback( - shouldAbort => { + signal => { catchNetworkErrors(async () => { if (!metaData) return - if (shouldAbort()) return + if (signal.aborted) return setStateContext('tree-loading') const { userName, repoName, branchName } = metaData @@ -36,7 +36,7 @@ export function useVisibleNodesGenerator(metaData: MetaData | null) { true, config.accessToken, ) - if (shouldAbort()) return + if (signal.aborted) return setStateContext('tree-rendering') diff --git a/src/utils/hooks/useAbortableEffect.ts b/src/utils/hooks/useAbortableEffect.ts new file mode 100644 index 0000000..2e35c5a --- /dev/null +++ b/src/utils/hooks/useAbortableEffect.ts @@ -0,0 +1,19 @@ +import { useEffect } from 'react' + +/** + * This effect addresses such a problem: + * the later effect ends earlier than the previous one, and the previous effect overlaps later effect's result. + */ +export function useAbortableEffect( + effect: (shouldAbort: AbortSignal) => (() => void | undefined) | void, +) { + useEffect(() => { + const abortController = new AbortController() + // The previous effect should stop running if the signal indicates should abort + const defect = effect(abortController.signal) + return () => { + abortController.abort() + defect?.() + } + }, [effect]) +} diff --git a/src/utils/hooks/useSequentialEffect.ts b/src/utils/hooks/useSequentialEffect.ts deleted file mode 100644 index 861e5df..0000000 --- a/src/utils/hooks/useSequentialEffect.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { useEffect } from 'react' - -/** - * This effect addresses such a problem: - * the later effect ends earlier than the previous one, and the previous effect overlaps later effect's result. - */ -export function useSequentialEffect( - effect: (shouldAbort: () => boolean) => (() => void | undefined) | void, -) { - useEffect(() => { - // The previous effect should stop running if shouldAbort returns true. - let end = false - const shouldAbort = () => end - const defect = effect(shouldAbort) - return () => { - end = true - defect?.() - } - }, [effect]) -}