fix: guard sparse preset async state (#3572)

This commit is contained in:
Neil
2026-05-30 02:27:20 -07:00
committed by GitHub
parent 6d70a57246
commit b7a625e0f2
3 changed files with 27 additions and 4 deletions
@@ -4,6 +4,7 @@ import type { SparsePreset } from '../../../../shared/types'
import { useAppStore } from '../../store'
import { cn } from '@/lib/utils'
import { parseSparsePresetDirectories } from '@/lib/sparse-preset-draft'
import { useMountedRef } from '@/hooks/useMountedRef'
import { Button } from '../ui/button'
import { Input } from '../ui/input'
import { Label } from '../ui/label'
@@ -59,6 +60,7 @@ export function SparsePresetSettingsSection({
const [draft, setDraft] = useState<SparsePresetDraft | null>(null)
const [submitting, setSubmitting] = useState(false)
const [confirmingDeleteId, setConfirmingDeleteId] = useState<string | null>(null)
const mountedRef = useMountedRef()
useEffect(() => {
if (presets === undefined) {
@@ -119,11 +121,13 @@ export function SparsePresetSettingsSection({
name: trimmedName,
directories: parsedDirectories.directories
})
if (saved) {
if (saved && mountedRef.current) {
setDraft(null)
}
} finally {
setSubmitting(false)
if (mountedRef.current) {
setSubmitting(false)
}
}
}
@@ -5,6 +5,7 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
import { useAppStore } from '@/store'
import { cn } from '@/lib/utils'
import { parseSparsePresetDirectories } from '@/lib/sparse-preset-draft'
import { useMountedRef } from '@/hooks/useMountedRef'
import type { SparsePreset } from '../../../../shared/types'
type SparseCheckoutPresetSelectProps = {
@@ -41,6 +42,7 @@ export default function SparseCheckoutPresetSelect({
const [submitting, setSubmitting] = useState(false)
const nameInputRef = useRef<HTMLInputElement>(null)
const nameInputFocusFrameRef = useRef<number | null>(null)
const mountedRef = useMountedRef()
const visiblePresets = presetsForRepo ?? presets
const presetsLoaded = presetsForRepo !== undefined
@@ -147,7 +149,7 @@ export default function SparseCheckoutPresetSelect({
name: trimmedName,
directories: parsedDirectories.directories
})
if (saved) {
if (saved && mountedRef.current) {
if (draft.mode === 'new' || selectedPresetId === saved.id) {
onSelectPreset(saved)
}
@@ -155,11 +157,14 @@ export default function SparseCheckoutPresetSelect({
setOpen(false)
}
} finally {
setSubmitting(false)
if (mountedRef.current) {
setSubmitting(false)
}
}
}, [
canSave,
draft,
mountedRef,
onSelectPreset,
parsedDirectories,
repoId,
+14
View File
@@ -0,0 +1,14 @@
import { useEffect, useRef, type MutableRefObject } from 'react'
export function useMountedRef(): MutableRefObject<boolean> {
const mountedRef = useRef(true)
useEffect(() => {
mountedRef.current = true
return () => {
mountedRef.current = false
}
}, [])
return mountedRef
}