Files
aliasvault/browser-extensions/chrome/src/hooks/useMinDurationLoading.ts
Leendert de Borst aa1df77400 Refactor (#541)
2025-02-01 11:09:08 +01:00

59 lines
1.8 KiB
TypeScript

import { useState, useEffect, useCallback, useRef } from 'react';
/**
* Hook that ensures a loading state persists for a minimum duration before being set to false.
* This improves the user experience by preventing the loading state from flickering.
*
* @param initialState - Initial loading state
* @param minDuration - Minimum duration in milliseconds
* @returns [isLoading, setIsLoading] - Loading state and setter
*/
export const useMinDurationLoading = (
initialState: boolean = false,
minDuration: number = 300
): [boolean, (value: boolean) => void] => {
const [isLoading, setIsLoading] = useState(initialState);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const startTimeRef = useRef<number | null>(null);
const setLoadingState = useCallback((value: boolean) => {
if (value) {
// Starting to load
setIsLoading(true);
startTimeRef.current = Date.now();
} else {
// Finishing loading - ensure minimum duration
const elapsedTime = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
const remainingTime = Math.max(0, minDuration - elapsedTime);
if (remainingTime === 0) {
setIsLoading(false);
} else {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setIsLoading(false);
}, remainingTime);
}
}
}, [minDuration]);
// Handle initial loading state only once
useEffect(() => {
if (initialState) {
setIsLoading(true);
startTimeRef.current = Date.now();
}
}, [initialState, setIsLoading]);
useEffect(() => {
return (): void => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return [isLoading, setLoadingState];
};