Search code examples
reactjsformikyup

Keep showing error message in Formik field select and Yup validation


I am trying to use formik and yup valiation first time, I have created a Select Field and have put some options , after selecting the option everytime it keep showing the validation error message ,

can anyone help me to fix it

the codesandbox link for error

https://codesandbox.io/s/sweet-dubinsky-w6cmws

    const InvestmentDetail = ({ data, changeValue }) => {
      return (
        <div className="text-2xl flex flex-col w-full justify-between container w-[1128px] gap-[42px] pt-[35px] pb-[50px] ">
          {investmentDetails.map((i, _i) => {
            return (
              <>
                <div>
                  <div className="text-[22px]"> {i.label} </div>
                  <div className="text-lg text-[#404040]"> {i.desc}</div>
                </div>
                <div className="flex flex-col w-full">
                  <Field
                    as="select"
                    name={i.label}
                    id="dropdown"
                    className="appearance-none relative !w-full p-[16px] h-[4.06rem] border-[#787878] rounded-[6px] border-solid border-[1px] bg-[#fff]"
                    value={data[i.label]}
                    onChange={(e) => changeValue(i.label, e.target.value)}
                  >
                    <option value="" className="text-2xl">
                      Select
                    </option>
    
                    {i.options.map((i) => (
                      <>
                        <option key={i} value={i} className="text-2xl">
                          {i}
                        </option>
                        <br />
                      </>
                    ))}
                  </Field>
                  <ErrorMessage
                    name={i.label}
                    component="div"
                    className="error  bottom-[-10px] text-[red] text-xl"
                  />
                </div>
              </>
            );
          })}
        </div>
      );
    };
    
    export default function App() {
      const [formData, setFormData] = useState(initialStates);
      useEffect(() => {}, [formData, setFormData]);
      const changeValue = (key, value) => {
        setFormData((prevData) => ({
          ...prevData,
          [key]: value
        }));
      };
    
      return (
        <>
          <Formik
            initialValues={initialValues}
            validationSchema={validationSchema}
            onSubmit={() => console.log("high")}
          >
            <Form>
              <InvestmentDetail data={formData} changeValue={changeValue} />
            </Form>
          </Formik>{" "}
        </>
      );

}

validation schema and initial states :

import * as Yup from "yup";
export const investmentDetails = [
  {
    label: "Account Type",
    desc: "",
    options: ["Saving", "Current"]
  },
  {
    label: "Portfolio/Strategy Name",
    desc: "",
    options: ["Saving", "Current"]
  },
  {
    label: "Fund Fees Category",
    desc: "Fees preview according to selection",
    options: ["Saving", "Current"]
  },
  {
    label: "Investment Category",
    desc: "Preview only when systematic transfer plan is selected",
    options: ["Saving", "Current"]
  },
  {
    label: "Country of Tax Residency",
    desc: "Preview only when systematic transfer plan is selected",
    options: ["Saving", "Current"]
  },
  {
    label: "No. of Account Holders",
    desc: "Preview only when systematic transfer plan is selected",
    options: ["Saving", "Current"]
  },

  {
    label: "Investment Mode",
    desc: "Preview only when systematic transfer plan is selected",
    options: ["Saving", "Current"]
  }
];

export const initialValues = {
  "Account Type": "",
  "Portfolio/Strategy Name": "",
  "Fund Fees Category": "",
  "Investment Category": "",
  "Communication Address": "",
  "Country of Tax Residency": "",
  "No. of Account Holders": "",
  "Quantum of Investment": "",
  "Investment Mode": ""
};

export const initialStates = {
  "Account Type": "",
  "Portfolio/Strategy Name": "",
  "Fund Fees Category": "",
  "Investment Category": "",
  "Communication Address": "",
  "Country of Tax Residency": "",
  "No. of Account Holders": 1,
  "Quantum of Investment": "",
  "Investment Mode": ""
};
export const validationSchema = Yup.object().shape({
  "Account Type": Yup.string().required("Required"),
  "Portfolio/Strategy Name": Yup.string().required("Required"),
  "Fund Fees Category": Yup.string().required("Required"),
  "Investment Category": Yup.string().required("Required"),
  "Country of Tax Residency": Yup.string().required("Required"),
  "No. of Account Holders": Yup.number()
    .required("Required")
    .min(1, "Should be at least 1"),

  "Investment Mode": Yup.string().required("Required")
});

Solution

  • You should use formik features to access or change values in app and prevent set field value on onChange property of Field component because <Field/> automatically set value as the document has mentioned.

    <Field /> will automagically hook up inputs to Formik. It uses the name attribute to match up with Formik state. will default to an HTML element.

        <Field
          as="select"
          name={i.label}
          id="dropdown"
          className="appearance-none relative !w-full p-[16px] h-[4.06rem] border-[#787878] rounded-[6px] border-solid border-[1px] bg-[#fff]"
          value={data[i.label]}
        >
          <option value="" className="text-2xl">
            Select
          </option>
    
          {i.options.map((i) => (
            <>
              <option key={i} value={i} className="text-2xl">
                {i}
              </option>
              <br />
            </>
          ))}
        </Field>
    

    Actually formData setState in App component is redundant and you will access to values on onSubmit callback as follows:

    <Formik
      validateOnChange={true}
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
    >
      <Form>
        <InvestmentDetail data={formData} changeValue={changeValue} />
      </Form>
    </Formik>