DEV Community

Cover image for Automatically submitting forms in react-hook-form
Yehor Kardash
Yehor Kardash

Posted on

Automatically submitting forms in react-hook-form

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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 };
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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

Snippet source code

Top comments (0)