1- import { useCallback , useState } from 'react'
1+ import { useCallback , useState , useRef } from 'react'
22import type { GitWorkerClient } from '../utils/gitWorkerClient'
33import type { AppStatus } from '../types/appStatus'
44import { isBinaryPath , LARGE_REPO_FILE_THRESHOLD , type FileDiffStatus , type FileTreeNode } from '@gitcontext/core'
@@ -18,6 +18,9 @@ export function useFileTree(setAppStatus?: (s: AppStatus) => void) {
1818 const [ selectedPaths , setSelectedPaths ] = useState < Set < string > > ( new Set ( ) )
1919 const [ isComputing , setIsComputing ] = useState < boolean > ( false )
2020
21+ // Track diff computation request IDs to prevent race conditions
22+ const diffRequestIdRef = useRef ( 0 )
23+
2124 const buildTreeFromPaths = useCallback ( ( allPaths : string [ ] , diffMap : Map < string , FileDiffStatus > ) : { tree : FileTreeNode ; statusByPath : Map < string , FileDiffStatus > } => {
2225 const root : FileTreeNode = { name : '' , path : '' , type : 'dir' , children : [ ] }
2326 const dirMap = new Map < string , FileTreeNode > ( )
@@ -85,21 +88,35 @@ export function useFileTree(setAppStatus?: (s: AppStatus) => void) {
8588 setExpandedPaths ( new Set ( ) )
8689 return
8790 }
91+
92+ // Increment request ID to track this specific diff computation
93+ const requestId = ++ diffRequestIdRef . current
8894 setIsComputing ( true )
89-
95+
9096 try {
9197 setAppStatus ?.( { state : 'LOADING' , task : 'diff' , message : 'Computing file differences…' , progress : 25 } )
9298 try { console . info ( '[app-status]' , { state : 'LOADING' , task : 'diff' , message : 'Computing file differences…' , progress : 25 } ) } catch { }
9399 setProgress ?.( { message : 'Computing file differences…' , percent : 25 } )
94-
100+
95101 const res = await gitClient . diff ( baseBranch , compareBranch )
102+
103+ // Check if this request is still the latest one (prevent race condition)
104+ if ( requestId !== diffRequestIdRef . current ) {
105+ return // A newer diff request has been made, ignore this result
106+ }
107+
96108 setDiffFiles ( res . files )
97109
98110 setProgress ?.( { message : 'Fetching file list…' , percent : 50 } )
99111 setAppStatus ?.( { state : 'LOADING' , task : 'diff' , message : 'Fetching file list…' , progress : 50 } )
100112 try { console . info ( '[app-status]' , { state : 'LOADING' , task : 'diff' , message : 'Fetching file list…' , progress : 50 } ) } catch { }
101113 const baseList = await gitClient . listFiles ( baseBranch )
102114 const compareList = await gitClient . listFiles ( compareBranch )
115+
116+ // Check again after async operations
117+ if ( requestId !== diffRequestIdRef . current ) {
118+ return
119+ }
103120 const diffMap = new Map < string , FileDiffStatus > ( )
104121 for ( const f of res . files ) diffMap . set ( f . path , f . type as FileDiffStatus )
105122 // Build union from both sides to keep unchanged files present on either side
@@ -108,6 +125,12 @@ export function useFileTree(setAppStatus?: (s: AppStatus) => void) {
108125 setAppStatus ?.( { state : 'LOADING' , task : 'diff' , message : 'Building file tree…' , progress : 75 } )
109126 try { console . info ( '[app-status]' , { state : 'LOADING' , task : 'diff' , message : 'Building file tree…' , progress : 75 } ) } catch { }
110127 const { tree, statusByPath : statusMap } = buildTreeFromPaths ( Array . from ( union ) , diffMap )
128+
129+ // Final check before committing all state updates
130+ if ( requestId !== diffRequestIdRef . current ) {
131+ return
132+ }
133+
111134 setFileTree ( tree )
112135 setStatusByPath ( statusMap )
113136
0 commit comments