是的,react-hook-form:如何在表单中创建条件必填字段?

Yup and react-hook-form: how to create conditional mandatory fields in a form?

阿门德

我有一个使用 Material UI、react-hook-from 和是的表单。

表单包含三组无线电组(例如:radio-g1、radio-g2、radio-g3),并且用户必须 select radio-g1、radio-g2 中的至少两个选项.此外,如果他们从 radio-g2 选择选项 'other',将显示另一个必填字段 radio-g3。

最后,radio-g3 在隐藏时不是强制性的。

如有任何帮助,我们将不胜感激。 这是一些示例代码:

const schema = yup.object().shape({
  radioG1: yup.string().required("Please select an Avenger"),
  radioG2: yup.string().required("Please select an Avenger"),
  radioG3: yup.string().required("Please select an Avenger")
});

const App = () => {
  const [show, setShow] = useState(false);

  const methods = useForm({
    mode: "all",
    shouldUnregister: true,
    resolver: yupResolver(schema)
  });

  const {
    handleSubmit,
    control,
    formState: { errors }
  } = methods;

  const onSubmit = (data) => {
    alert(JSON.stringify(data));
  };

  return (
    <FormProvider {...methods}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <FormControl
          variant="outlined"
          component="fieldset"
          margin="normal"
          error={!!errors.radioG1}
        >
          <FormLabel component="legend">Favorite Avengers:</FormLabel>
          <Controller
            render={({ field }) => (
              <RadioGroup {...field}>
                <FormControlLabel
                  value="Iron Man"
                  control={<Radio />}
                  label="Iron Man"
                />
                <FormControlLabel
                  value="Captain America"
                  control={<Radio />}
                  label="Captain America"
                />
              </RadioGroup>
            )}
            name="radioG1"
            control={control}
          />
          {errors.radioG1 ? (
            <FormHelperText>{errors?.radioG1?.message}</FormHelperText>
          ) : null}
        </FormControl>
        <div>
          <FormControl
            variant="outlined"
            component="fieldset"
            margin="normal"
            error={!!errors.radioG2}
          >
            <FormLabel component="legend">Favorite Avengers 2:</FormLabel>
            <Controller
              render={({ field }) => (
                <RadioGroup {...field}>
                  <FormControlLabel
                    value="Thor"
                    control={<Radio />}
                    label="Thor"
                  />
                  <FormControlLabel
                    value="Black Widow"
                    control={<Radio />}
                    label="Black Widow"
                  />
                </RadioGroup>
              )}
              name="radioG2"
              control={control}
            />
            {errors.radioG2 ? (
              <FormHelperText>{errors?.radioG2?.message}</FormHelperText>
            ) : null}
          </FormControl>
        </div>
        <Box mt={2} mb={2}>
          <Alert severity="info">
            <Link
              color="primary"
              underline="always"
              component="button"
              onClick={() => setShow(!show)}
            >
              Meh, I don't like these Avengers, SHOW MORE.
            </Link>
          </Alert>

          {show ? <OtherAvengers control={control} errors={errors} /> : null}
        </Box>
        <Box>
          <Button
            size="large"
            variant="contained"
            type="submit"
            color="primary"
          >
            Submit
          </Button>
        </Box>
      </form>
    </FormProvider>
  );
};

const OtherAvengers = ({ control, errors }) => {
  return (
    <div>
      <FormControl
        variant="outlined"
        component="fieldset"
        margin="normal"
        error={!!errors.radioG3}
      >
        <FormLabel component="legend">Favorite Avengers 3:</FormLabel>
        <Controller
          render={({ field }) => (
            <RadioGroup {...field}>
              <FormControlLabel value="Hulk" label="Hulk" control={<Radio />} />
              <FormControlLabel
                value="Ant-Man"
                label="Ant-Man"
                control={<Radio />}
              />
            </RadioGroup>
          )}
          name="radioG3"
          control={control}
        />
        {errors.radioG3 ? (
          <FormHelperText>{errors?.radioG3?.message}</FormHelperText>
        ) : null}
      </FormControl>
    </div>
  );
};

Codesandbox 在这里 https://codesandbox.io/s/conditional-mandatory-fields-7xojm?file=/src/index.jsx

您可以使用 when() 并将您的 radioG1radioG2radioG3 传递给条件。

像这样:

let schema = yup.object({
  isBig: yup.boolean(),
  count: yup.number().when('isBig', (isBig, schema) => {
    return isBig ? schema.min(5) : schema.min(0);
  }),
});

根据上面@Ryan Le 的回答,这里是工作代码:

const schema = yup.object().shape({
  radioG1: yup.string().required("Please select an Avenger"),
  radioG2: yup.string().required("Please select an Avenger"),
  radioG3: yup.string().when("radioG2", {
    is: "other",
    then: yup.string().required('can\'t be blank')
  })
});

const App = () => {
  const methods = useForm({
    mode: "all",
    shouldUnregister: true,
    resolver: yupResolver(schema)
  });

  const {
    handleSubmit,
    control,
    watch,
    formState: { errors }
  } = methods;

  let watchOther = watch("radioG2");
  const onSubmit = (data) => {
    alert(JSON.stringify(data));
  };

  return (
    <FormProvider {...methods}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <FormControl
          variant="outlined"
          component="fieldset"
          margin="normal"
          error={!!errors.radioG1}
        >
          <FormLabel component="legend">Favorite Avenger:</FormLabel>
          <Controller
            render={({ field }) => (
              <RadioGroup {...field}>
                <FormControlLabel
                  value="Iron Man"
                  control={<Radio />}
                  label="Iron Man"
                />
                <FormControlLabel
                  value="Captain America"
                  control={<Radio />}
                  label="Captain America"
                />
              </RadioGroup>
            )}
            name="radioG1"
            control={control}
          />
          {errors.radioG1 ? (
            <FormHelperText>{errors?.radioG1?.message}</FormHelperText>
          ) : null}
        </FormControl>
        <div>
          <FormControl
            variant="outlined"
            component="fieldset"
            margin="normal"
            error={!!errors.radioG2}
          >
            <FormLabel component="legend">Favorite Avenger 2:</FormLabel>
            <Controller
              render={({ field }) => (
                <RadioGroup {...field}>
                  <FormControlLabel
                    value="Thor"
                    control={<Radio />}
                    label="Thor"
                  />
                  <FormControlLabel
                    value="Black Widow"
                    control={<Radio />}
                    label="Black Widow"
                  />
                  <FormControlLabel
                    value="other"
                    control={<Radio />}
                    label="Other"
                  />
                </RadioGroup>
              )}
              name="radioG2"
              control={control}
            />
            {errors.radioG2 ? (
              <FormHelperText>{errors?.radioG2?.message}</FormHelperText>
            ) : null}
          </FormControl>
        </div>

        {watchOther === "other" ? (
          <OtherAvengers control={control} errors={errors} />
        ) : null}

        <Box>
          <Button
            size="large"
            variant="contained"
            type="submit"
            color="primary"
          >
            Submit
          </Button>
        </Box>
      </form>
    </FormProvider>
  );
};

const OtherAvengers = ({ control, errors }) => {
  return (
    <div>
      <FormControl
        variant="outlined"
        component="fieldset"
        margin="normal"
        error={!!errors.radioG3}
      >
        <FormLabel component="legend">Favorite Avenger 3:</FormLabel>
        <Controller
          render={({ field }) => (
            <RadioGroup {...field}>
              <FormControlLabel value="Hulk" label="Hulk" control={<Radio />} />
              <FormControlLabel
                value="Ant-Man"
                label="Ant-Man"
                control={<Radio />}
              />
            </RadioGroup>
          )}
          name="radioG3"
          control={control}
        />
        {errors.radioG3 ? (
          <FormHelperText>{errors?.radioG3?.message}</FormHelperText>
        ) : null}
      </FormControl>
    </div>
  );
};