reactjstypescriptreact-hook-formyup

How to dynamically update Yup validation schema in React Hook Form when a field value changes (using yup.lazy)?


I'm using react-hook-form with the latest version of yup, and I'm trying to implement dynamic validation that depends on a type field selected by the user. The validation schema is generated using yup.lazy, and it returns different rules based on the current value of type.

Here’s how I'm initializing the form:

const defaultValues = getDefaultValues(type, dataToEdit);
const schema = getSchema(t);

const methods = useForm<any>({
  reValidateMode: 'onChange',
  resolver: yupResolver(schema),
  defaultValues,
  context: { rawMaterials, defaultValues },
});

Here’s a simplified version of my getSchema function:

const getSchema = (t) =>
  yup.lazy((value, context) => {
    console.log('Type called with context:', context);
    console.log('Schema called with:', value);

    return yup.object().shape({
      purchaseOrderTasks: yup.array().of(
        yup.object().shape({
          cigar: yup.string().when([], {
            is: () => value.type === PURCHASE_ORDER_TYPES.CIGAR,
            then: (schema) => schema.required(t('validation.required')),
            otherwise: (schema) => schema.nullable(),
          }),
          tobacco: yup.string().when([], {
            is: () => value.type === PURCHASE_ORDER_TYPES.TOBACCO,
            then: (schema) => schema.required(t('validation.required')),
            otherwise: (schema) => schema.nullable(),
          }),
          // ... more fields
        })
      ),
    });
  });

What I'm trying to achieve When the user changes the value of the type field inside the form, the Yup validation should update immediately to reflect the new rules (e.g., require cigar if type === CIGAR, or tobacco if type === TOBACCO, etc).

The issue type never changes enter image description here The schema is created once during useForm initialization.

When the user changes type, the form shows the correct fields, but the validation schema does not update accordingly.

Since yup.lazy depends on value.type, it seems like value passed to the resolver is stale or not updated.

I want to:

Keep react-hook-form and yup

Dynamically adjust validation logic based on form values (especially type)

Any best practices or patterns for this?


Solution

  • It is my mistake; I added tested code for validation/test before any updated. Value params in lazy are correctly updated.