2022-07-19

Isn't this validation synchronous?

Taking a look at this commit in the Formik.tsx file, the validation was moved from (in the case of touched as an example):

 React.useEffect(() => {
    if (
      prevState.touched !== state.touched &&
      !!validateOnBlur &&
      !state.isSubmitting &&
      isMounted.current != null
    ) {
      const [validate, cancel] = makeCancelable(validateForm());
      validate.then(x => x).catch(x => x); // catch the rejection silently
      return cancel;
    }
    return;
  }, [
    prevState.touched,
    state.isSubmitting,
    state.touched,
    validateForm,
    validateOnBlur,
    isMounted,
  ]);

to here:

 const setFieldTouched = React.useCallback(
    (
      field: string,
      touched: boolean = true,
      shouldValidate: boolean = true
    ) => {
      dispatch({
        type: 'SET_FIELD_TOUCHED',
        payload: {
          field,
          value: touched,
        },
      });
      return validateOnBlur && shouldValidate
        ? validateFormWithLowPriority(state.values)
        : Promise.resolve();
    },
    [validateFormWithLowPriority, state.values, validateOnBlur]
  );

Jumping to the current implementation, it looks like this:

  const setFieldTouched = useEventCallback(
    (field: string, touched: boolean = true, shouldValidate?: boolean) => {
      dispatch({
        type: 'SET_FIELD_TOUCHED',
        payload: {
          field,
          value: touched,
        },
      });
      const willValidate =
        shouldValidate === undefined ? validateOnBlur : shouldValidate;
      return willValidate
        ? validateFormWithHighPriority(state.values)
        : Promise.resolve();
    }
  );

But why and how do the latter two ensure that the validation will be run with the "freshest" values? With the effect you might dispatch a change, then a blur (both will change the state). The state will then change at some point causing the effect to then run with the current values.

In the latter, the validation - when following the trail of calls - should still run synchronously (executor function of a promise is executed synchronously) - only the setting of the errors will wait until the promise is done (has explicit then). This should mean that when i call setFieldValue and then setFieldTouched immediately after, that the state will still be the old one (since state change is asynchronous). An example would be that i could dispatch a change to a state, and try to access the same state immediately after, which will still be the old state (code sandbox).

However when looking at this code sandbox, the values passed to validate (from the validation flow in setFieldTouched are the actual fresh values. I don't see why this is the case...this might very well be a mistaken interpretation of the flow on my side, but that is why i pose this question.



No comments:

Post a Comment