diff --git a/src/components/FileExplorer.tsx b/src/components/FileExplorer.tsx index 931e1ad..587a643 100644 --- a/src/components/FileExplorer.tsx +++ b/src/components/FileExplorer.tsx @@ -15,6 +15,7 @@ import { run } from 'utils/general' import { useLoadedContext } from 'utils/hooks/useLoadedContext' import { useOnLocationChange } from 'utils/hooks/useOnLocationChange' import { useOnPJAXDone } from 'utils/hooks/usePJAX' +import { useSequentialEffect } from 'utils/hooks/useSequentialEffect' import { VisibleNodes } from 'utils/VisibleNodesGenerator' import { SideBarStateContext } from '../containers/SideBarState' import { DiffStatGraph } from './DiffStatGraph' @@ -74,16 +75,22 @@ const RawFileExplorer: React.FC = function RawFileExplor const stateContext = useLoadedContext(SideBarStateContext) const state = stateContext.value - React.useEffect(() => { - setUpTree({ - metaData, - config: { - compressSingletonFolder, - accessToken, - }, - stateContext, - }) - }, [setUpTree, metaData, compressSingletonFolder, accessToken]) + useSequentialEffect( + checker => { + setUpTree( + { + metaData, + config: { + compressSingletonFolder, + accessToken, + }, + stateContext, + }, + checker, + ) + }, + [setUpTree, metaData, compressSingletonFolder, accessToken], + ) React.useEffect(() => { focusFileExplorer() diff --git a/src/driver/core/FileExplorer.ts b/src/driver/core/FileExplorer.ts index b17371e..8ca0de9 100644 --- a/src/driver/core/FileExplorer.ts +++ b/src/driver/core/FileExplorer.ts @@ -48,10 +48,11 @@ export const setUpTree: BoundMethodCreator< { stateContext: SideBarStateContextShape } & Required> & { config: Pick }, + () => boolean, ] > = dispatch => - ({ stateContext, metaData, config }) => { + ({ stateContext, metaData, config }, checker) => { const { props: { catchNetworkErrors }, } = dispatch.get() @@ -59,7 +60,9 @@ export const setUpTree: BoundMethodCreator< catchNetworkErrors(async () => { const { userName, repoName, branchName } = metaData + if (!checker()) return stateContext.onChange('tree-loading') + const { root: treeRoot, defer = false } = await platform.getTreeData( { branchName: branchName, @@ -71,6 +74,7 @@ export const setUpTree: BoundMethodCreator< config.accessToken, ) + if (!checker()) return stateContext.onChange('tree-rendering') dispatch.set({ defer }) @@ -82,21 +86,29 @@ export const setUpTree: BoundMethodCreator< return root }, }) + + if (!checker()) return dispatch.set({ visibleNodesGenerator }) - visibleNodesGenerator.onUpdate(visibleNodes => dispatch.set({ visibleNodes })) + + visibleNodesGenerator.onUpdate(visibleNodes => { + if (!checker()) return + dispatch.set({ visibleNodes }) + }) if (platform.shouldExpandAll?.()) { const unsubscribe = visibleNodesGenerator.onUpdate(visibleNodes => { unsubscribe() - visibleNodes.nodes.forEach(node => - dispatch.call(toggleNodeExpansion, node, { recursive: true }), - ) + visibleNodes.nodes.forEach(node => { + if (!checker()) return + dispatch.call(toggleNodeExpansion, node, { recursive: true }) + }) }) } else { const targetPath = platform.getCurrentPath(metaData.branchName) - if (targetPath) dispatch.call(goTo, targetPath) + if (targetPath && checker()) dispatch.call(goTo, targetPath) } + if (!checker()) return stateContext.onChange('tree-rendered') }) } diff --git a/src/utils/hooks/useSequentialEffect.ts b/src/utils/hooks/useSequentialEffect.ts new file mode 100644 index 0000000..3b7497f --- /dev/null +++ b/src/utils/hooks/useSequentialEffect.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef } 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: (checker: () => boolean) => (() => void | undefined) | void, + deps: React.DependencyList = [], +) { + const sequenceCounter = useRef(0) + useEffect(() => { + // The counter is incremented every time a new effect is added. + // And the previous effect should stop going forward by finding checker returning false. + const counter = ++sequenceCounter.current + const checker = () => counter === sequenceCounter.current + return effect(checker) + }, deps) +}