React Hook Form is a powerful library for managing forms in React, offering excellent performance and a flexible API. However, there are scenarios where you might want to create a form that does not behave exactly like a standard form. Sometimes form data needs to be submitted automatically when changes occur. This is particularly useful for forms that require real-time validation and submission, such as search forms or dynamic filtering interfaces.
Let's say, we have a simple search form for emails.
import { useForm } from 'react-hook-form';
interface FormValues {
content: string;
email: string;
}
const SearchForm = () => {
const { register, handleSubmit } = useForm<FormValues>();
const onSubmit = (data: FormValues) => {
console.log('Form submitted:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>Search by</div>
<div>
<label>Content:</label>
<input {...register('content')} />
</div>
<div>
<label>Email:</label>
<input {...register('email')} />
</div>
</form>
);
};
But then we might want to remove the "Submit" button and submit data without it. To do that, we can create a custom reusable hook that will automatically submit the form when it changes.
import { debounce } from 'lodash';
import { useCallback, useEffect, useState } from 'react';
import { type UseFormWatch, type FieldValues, type UseFormTrigger, type Path } from 'react-hook-form';
interface AutoSubmitProps<T extends FieldValues> {
trigger: UseFormTrigger<T>;
watch: UseFormWatch<T>;
excludeFields?: Path<T>[];
onSubmit: () => void;
onValidationFailed?: () => void;
debounceTime?: number;
}
/**
* Automatically submit data when it's changed
*/
export const useAutoSubmit = <T extends FieldValues>({
trigger,
watch,
onSubmit,
debounceTime = 500,
excludeFields,
onValidationFailed,
}: AutoSubmitProps<T>) => {
const [isSubmiting, setIsSubmiting] = useState(false);
const debouncedSumbit = useCallback(
debounce((submitFn: () => void) => {
submitFn();
}, debounceTime),
[],
);
useEffect(() => {
const subscription = watch((_data, info) => {
if (info?.type !== 'change') return;
if (info.name && excludeFields?.includes(info.name)) return;
setIsSubmiting(true);
trigger()
.then((valid) => {
if (valid) debouncedSumbit(onSubmit);
else onValidationFailed?.();
})
.finally(() => setIsSubmiting(false));
});
return () => subscription.unsubscribe();
}, [watch, onSubmit]);
return { isSubmiting };
};
How it works
-
trigger
: Triggers validation for the entire form or specific fields. -
watch
: Monitors form data changes. -
onSubmit
: The function to execute when the form is successfully validated. -
debounceTime
: Controls how often the form should be submitted after changes (default is 500ms). -
onValidationFailed
: An optional callback for handling validation failures
The hook automatically triggers form validation when a field changes. If the validation is successful, it debounces the submission to avoid excessive requests.
Usage
import { useForm } from 'react-hook-form';
import { useAutoSubmit } from './useAutoSubmit';
interface FormValues {
content: string;
email: string;
}
const SearchForm = () => {
const { register, handleSubmit, trigger, watch } = useForm<FormValues>();
const onSubmit = (data: FormValues) => {
console.log('Form submitted:', data);
};
useAutoSubmit({
trigger,
watch,
onSubmit: handleSubmit(onSubmit),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>Search by</div>
<div>
<label>Content:</label>
<input {...register('content')} />
</div>
<div>
<label>Email:</label>
<input {...register('email')} />
</div>
</form>
);
};
The useAutoSubmit
hook simplifies the process of automatically submitting forms in React applications. By using this hook, you can ensure that your forms are always up-to-date with the latest user input, reducing the need for manual submissions and enhancing the overall user experience
Top comments (0)