Search code examples
reactjsformikyup

How to use yup in stepper form


I make a stepper formik form and the objective is yup should validate each step of the form. this is my validation schema:

const schema = [
yup
  .object()
  .shape({
    field1: yup.string().required("cannot be empty"),
    field2: yup.string().required("cannot be empty"),
  }),
yup
  .object()
  .shape({
    field3: yup.string().required("cannot be empty"),
    field4: yup.string().required("cannot be empty"),
  }),
yup
  .object()
  .shape({
    field5: yup.string().required("cannot be empty"),
    field6: yup.string().required("cannot be empty"),
  }),

];

<Formik
    initialValues={initialValues}
    validationSchema={schema}
    onSubmit={_handleSubmit}
  >
    {({ isSubmitting, dirty, isValid, values, resetForm }) => (
      <Form>
        {_renderStepperForm(currentStep)}
        <Button
          size="sm"
          disabled={currentStep === 0}
          onClick={goToPreviousStep}
        >
          Previous
        </Button>
        <Button type="submit" size="sm" onClick={goToNextStep}>
          {currentStep + 1 === stepConstant?.length ? "save" : "Next"}
        </Button>
      </Form>
    )}
  </Formik>

but i got error massage "schema[(intermediate value)(intermediate value)(intermediate value)] is not a function". how should i setting up he validation schema?


Solution

  • The error "schema[(intermediate value)(intermediate value)(intermediate value)] is not a function" occurs because Formik expects a single validation schema object, not an array of schemas. You need to combine all your individual schemas into one. You can achieve this by merging the objects in the array. In your code you are passing the array of objects not singleton objects consisting of objects.

    Here's how you can set up the validation schema correctly:

      const schema = yup.object().shape({
      field1: yup.string().required("cannot be empty"),
      field2: yup.string().required("cannot be empty"),
      field3: yup.string().required("cannot be empty"),
      field4: yup.string().required("cannot be empty"),
      field5: yup.string().required("cannot be empty"),
      field6: yup.string().required("cannot be empty"),
    });
    

    Whereas you can use useState if you want to pass the array of objects for step-wise validation.

    const MyForm = () => {
      const [step, setStep] = useState(0);
    
      const isLastStep = step === stepSchemas.length - 1;
      const currentSchema = stepSchemas[step];
    
      const handleNext = () => {
        setStep((s) => s + 1);
      };
    
      const handlePrevious = () => {
        setStep((s) => s - 1);
      };
    
      return (
        <Formik
          initialValues={initialValues}
          validationSchema={currentSchema}
          onSubmit={isLastStep ? _handleSubmit : handleNext}
        > 
        {({ isSubmitting, dirty, isValid, values, resetForm }) => (
            <Form>
        // Form values here........
        </div>
            </Form>
          )}
        </Formik>
      );
    };