All files / libs/ext/formik/src/lib/hooks/use-formik-autosave useFormikAutosave.ts

100% Statements 32/32
100% Branches 6/6
100% Functions 1/1
100% Lines 32/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 331x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 5x 2x 2x 2x 3x 8x 8x  
import { useFormikContext, type FormikErrors, type FormikValues } from 'formik';
import { isEqual } from 'lodash-es';
import { useEffect, useRef } from 'react';
 
export type UseFormikAutosaveOptions<TValues extends FormikValues = FormikValues> = {
  /** Called with the current values. */
  onSave: (values: TValues, errors: FormikErrors<TValues>) => void;
  /** Time to wait when the values change before calling onSave. */
  timeoutMs?: number;
};
 
export const useFormikAutosave = <TValues extends FormikValues = FormikValues>({
  onSave,
  timeoutMs = 1000,
}: UseFormikAutosaveOptions<TValues>) => {
  // Keep a ref on the onSave function, so it does not reset the timeout if the function reference is unstable.
  const onSaveRef = useRef(onSave);
  onSaveRef.current = onSave;
 
  // Subscribe to values change.
  const { values, errors, initialValues, isSubmitting } = useFormikContext<TValues>();
 
  // When the values change, call the onSave function after timeoutMs.
  // Reset the timeout if values change again before timeoutMs expires.
  useEffect(() => {
    if (!isSubmitting && !isEqual(values, initialValues)) {
      const timeoutHandle = setTimeout(() => onSaveRef.current(values, errors), timeoutMs);
      return () => clearTimeout(timeoutHandle);
    }
    return undefined;
  }, [initialValues, values, errors, timeoutMs, isSubmitting]);
};