elements constructor улучшен
This commit is contained in:
111
src/hook/useDelayedSave.ts
Normal file
111
src/hook/useDelayedSave.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
|
||||
interface UseDelayedSaveOptions<T> {
|
||||
onSave: (data: T) => Promise<void>
|
||||
onSuccess?: (data: T) => void // Коллбек после успешного сохранения
|
||||
delay?: number // Задержка в миллисекундах (по умолчанию 2000мс)
|
||||
}
|
||||
|
||||
interface UseDelayedSaveReturn<T> {
|
||||
hasUnsavedChanges: boolean
|
||||
isSaving: boolean
|
||||
lastSaveError: string | null
|
||||
updateData: (data: T) => void
|
||||
manualSave: () => Promise<void>
|
||||
clearError: () => void
|
||||
}
|
||||
|
||||
export function useDelayedSave<T>({
|
||||
onSave,
|
||||
onSuccess,
|
||||
delay = 2000,
|
||||
}: UseDelayedSaveOptions<T>): UseDelayedSaveReturn<T> {
|
||||
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false)
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const [lastSaveError, setLastSaveError] = useState<string | null>(null)
|
||||
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||
const pendingDataRef = useRef<T | null>(null)
|
||||
|
||||
// Очистка таймера при размонтировании компонента
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const clearError = useCallback(() => {
|
||||
setLastSaveError(null)
|
||||
}, [])
|
||||
|
||||
const performSave = useCallback(
|
||||
async (data: T) => {
|
||||
if (isSaving) return
|
||||
|
||||
setIsSaving(true)
|
||||
setLastSaveError(null)
|
||||
|
||||
try {
|
||||
await onSave(data)
|
||||
setHasUnsavedChanges(false)
|
||||
pendingDataRef.current = null
|
||||
// Вызываем коллбек успешного сохранения
|
||||
onSuccess?.(data)
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Неизвестная ошибка'
|
||||
setLastSaveError(errorMessage)
|
||||
console.error('Ошибка при сохранении:', error)
|
||||
} finally {
|
||||
setIsSaving(false)
|
||||
}
|
||||
},
|
||||
[onSave, onSuccess, isSaving]
|
||||
)
|
||||
|
||||
const updateData = useCallback(
|
||||
(data: T) => {
|
||||
// Отменяем предыдущий таймер
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
}
|
||||
|
||||
// Сохраняем данные для отложенного сохранения
|
||||
pendingDataRef.current = data
|
||||
setHasUnsavedChanges(true)
|
||||
setLastSaveError(null)
|
||||
|
||||
// Устанавливаем новый таймер
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
if (pendingDataRef.current) {
|
||||
performSave(pendingDataRef.current)
|
||||
}
|
||||
}, delay)
|
||||
},
|
||||
[delay, performSave]
|
||||
)
|
||||
|
||||
const manualSave = useCallback(async () => {
|
||||
// Отменяем автоматическое сохранение
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
timeoutRef.current = null
|
||||
}
|
||||
|
||||
// Сохраняем немедленно, если есть несохранённые данные
|
||||
if (pendingDataRef.current) {
|
||||
await performSave(pendingDataRef.current)
|
||||
}
|
||||
}, [performSave])
|
||||
|
||||
return {
|
||||
hasUnsavedChanges,
|
||||
isSaving,
|
||||
lastSaveError,
|
||||
updateData,
|
||||
manualSave,
|
||||
clearError,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user