55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
|
|
import { useEffect, useRef, useState } from "react";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Hook for debounced form validation.
|
||
|
|
* Validates form data after the user stops typing for a specified delay.
|
||
|
|
*
|
||
|
|
* @param formData - The form data to validate
|
||
|
|
* @param validator - Function that validates the form data and returns field errors
|
||
|
|
* @param delay - Debounce delay in milliseconds (default: 500)
|
||
|
|
* @returns Object containing current errors and a function to manually trigger validation
|
||
|
|
*/
|
||
|
|
export function useDebouncedValidation<T>(
|
||
|
|
formData: T,
|
||
|
|
validator: (data: T) => Record<string, string>,
|
||
|
|
delay: number = 500
|
||
|
|
): {
|
||
|
|
errors: Record<string, string>;
|
||
|
|
setErrors: React.Dispatch<React.SetStateAction<Record<string, string>>>;
|
||
|
|
validate: (data?: T) => void;
|
||
|
|
} {
|
||
|
|
const [errors, setErrors] = useState<Record<string, string>>({});
|
||
|
|
const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||
|
|
const formDataRef = useRef<T>(formData);
|
||
|
|
|
||
|
|
// Keep formDataRef in sync with formData
|
||
|
|
useEffect(() => {
|
||
|
|
formDataRef.current = formData;
|
||
|
|
}, [formData]);
|
||
|
|
|
||
|
|
// Cleanup timeout on unmount
|
||
|
|
useEffect(() => {
|
||
|
|
return () => {
|
||
|
|
if (validationTimeoutRef.current) {
|
||
|
|
clearTimeout(validationTimeoutRef.current);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const validate = (data?: T) => {
|
||
|
|
// Clear any pending validation timeout
|
||
|
|
if (validationTimeoutRef.current) {
|
||
|
|
clearTimeout(validationTimeoutRef.current);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Debounce validation - wait for user to stop typing
|
||
|
|
validationTimeoutRef.current = setTimeout(() => {
|
||
|
|
const dataToValidate = data ?? formDataRef.current;
|
||
|
|
const newErrors = validator(dataToValidate);
|
||
|
|
setErrors(newErrors);
|
||
|
|
}, delay);
|
||
|
|
};
|
||
|
|
|
||
|
|
return { errors, setErrors, validate };
|
||
|
|
}
|