fix: strict limit exec order of multiple VisibleNodesGenerator instances

fix #218
This commit is contained in:
EnixCoda 2022-03-20 22:58:24 +08:00
parent dbdc3828ac
commit 1e72cad644
3 changed files with 54 additions and 16 deletions

View file

@ -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<Props & ConnectorState> = 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()

View file

@ -48,10 +48,11 @@ export const setUpTree: BoundMethodCreator<
{ stateContext: SideBarStateContextShape } & Required<Pick<Props, 'metaData'>> & {
config: Pick<Config, 'compressSingletonFolder' | 'accessToken'>
},
() => 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')
})
}

View file

@ -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)
}