使用yup使用条件字段进行表单验证

时间:2020-09-30 14:34:40

标签: javascript reactjs yup

我正在尝试有条件地渲染字段并提交数据。

但是在下面的代码片段中,我无法实现。问题是重新渲染发生,并且值不持久。

在大多数情况下,问题在于我正在拆分架构,因此,基于对字段呈现方式的选择的选择。

如何在适当保留验证和值的情况下提交数据。

到目前为止我尝试过的事情

App.js

import React, { useEffect, useState } from "react";
import "./styles.css";
import Select from "react-select";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers";
import { CITIZEN_OPTIONS, validationSchema } from "./util";
import { Resident, NonResident } from "./CitizenDetails";
const Fallback = () => null;

export default function App() {
  const [citizenValue, setCitizenValue] = useState(null);

  const { register, control, errors, watch, handleSubmit } = useForm({
    resolver: yupResolver(validationSchema),
    mode: "onBlur",
    reValidateMode: "onChange"
  });

  const watchCitizen = watch("citizen");

  useEffect(() => {
    setCitizenValue(watchCitizen?.value);
  }, [watchCitizen]);

  const citizenDetails = {
    resident: () => <Resident errors={errors} register={register} />,
    non_resident: () => (
      <NonResident errors={errors} control={control} register={register} />
    )
  };

  const onSubmit = (data) => {
    console.log(data);
  };

  const SelectedCitizenFields = citizenDetails[citizenValue] || Fallback;

  return (
    <div className="App">
      <Controller
        as={Select}
        control={control}
        name="citizen"
        options={CITIZEN_OPTIONS}
      ></Controller>
      <SelectedCitizenFields />
      <button onClick={handleSubmit(onSubmit)}>Submit Details</button>
    </div>
  );
}

CitizenDetails.js

import React, { Fragment, memo } from "react";
import { Controller } from "react-hook-form";
import Select from "react-select";

export const Resident = memo((props) => {
  const { errors, register } = props;
  return (
    <Fragment>
      <div className="field-group">
        <label>Enter first name</label>
        <input ref={register} name="first_name"></input>
        {errors?.first_name?.message && (
          <span>{errors.first_name.message}</span>
        )}
      </div>
      <div className="field-group">
        <label>Enter last name</label>
        <input ref={register} name="last_name"></input>
        {errors?.last_name?.message && <span>{errors.last_name.message}</span>}
      </div>
    </Fragment>
  );
});

export const NonResident = memo((props) => {
  const { errors, register, control } = props;
  return (
    <Fragment>
      <div className="field-group">
        <label>Enter passport number</label>
        <input ref={register} name="passport_number"></input>
        {errors?.passport_number?.message && (
          <span>{errors.passport_number.message}</span>
        )}
      </div>
      <div className="field-group">
        <label>Choose Country</label>
        <Controller as={Select} control={control} name="country" options={[]} />
        {errors?.country?.message && <span>{errors.country.message}</span>}
      </div>
      <div className="field-group">
        <label>Choose State</label>
        <Controller as={Select} control={control} name="state" options={[]} />
        {errors?.state?.message && <span>{errors.state.message}</span>}
      </div>
    </Fragment>
  );
});

util.js

import { object, string, number, lazy } from "yup";

export const CITIZEN_OPTIONS = [
  {
    label: "Resident",
    value: "resident"
  },
  {
    label: "Non-Resident",
    value: "non_resident"
  }
];

const required = () => "field is required";

const resident_schema = object({
  first_name: string().required(required).nullable(),
  last_name: string().required(required).nullable()
});

const non_resident_schema = object({
  passport_number: string().required(required).nullable(),
  country: object().required(required).nullable(),
  state: object().required(required).nullable()
});

export const validationSchema = lazy(({ citizen }) => {
  return citizen?.value === "resident" ? resident_schema : non_resident_schema;
});

这是codesandbox链接

0 个答案:

没有答案