React Flexible FormDocsExamplesGitHub
DocumentationOverviewGetting StartedTypeScriptAPIuseFormFielduseSubformuseFieldArrayuseConvertutilsExamplesSimple FormChakra UI FormForm with ArraySubformCustom useConvertForm State in ReduxForm with LoaderForm based on Material UIThrottled error validation

Throttled Validation

In complex forms doing validation after each change of any input (i.e. user clics a button on the keyboard) may be useless. So throttled or debounced validation can be implemented. This require to change internal of the form by providing custom useValidate hook


const useValidate: UseValidate<Address> = ({
  formControl: { values, setFieldError },
  resolver,
  context,
  criteriaMode,
}) => {
  const validator = useCallback(
    async (values: Address) => {
      const { errors } = resolver
        ? await resolver(values, context, {
            criteriaMode,
            shouldUseNativeValidation: false,
            fields: undefined,
          })
        : { errors: {} };
      return errors;
    },
    [resolver, context, criteriaMode],
  );

  const throttleFn = useMemo(
    () =>
      throttle(5000, async (values: Address) => {
        const newErrors = await validator(values);
        setFieldError("", newErrors);
      }),
    [validator, setFieldError],
  );

  useEffect(() => {
    throttleFn(values);
  }, [throttleFn, values]);

  return useCallback(() => validator(values), [validator, values]);
};

// ... Other code ... 

  const formControl = useForm<Address>({
    initialValues: {
      country: "",
      state: "",
      city: "",
      zipCode: "",
      street1: "",
      street2: undefined,
    },
    resolver,
    onSubmit,
    useValidate,
  });
import { ComponentProps, FC } from "react";

type Props = {
  error?: string | undefined;
  touched: boolean;
  label: string;
} & ComponentProps<"input">;

const SimpleInput: FC<Props> = ({ touched, error, label, style, ...rest }) => {
  const isInvalid = !!(error && touched);
  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        gap: "10px",
        ...(style ?? {}),
      }}
    >
      <label>{label}</label>
      <input style={{ border: "1px solid" }} {...rest} />
      <span style={{ color: isInvalid ? "red" : "inherit", whiteSpace: "pre" }}>
        {isInvalid ? error : " "}
      </span>
    </div>
  );
};

export default SimpleInput;