react-hook-form:使用 onBlur 模式时验证不起作用

aad*_*dlc 5 reactjs material-ui yup react-hook-form

我想用显示错误yup,并react-hook-form当用户选择超过5个复选框没有成功。

相反,选择第七个复选框时会显示错误。

这是简化的代码:

imports...

const schema = yup.object().shape({
  option: yup.array().max(5)
});
function App() {
  const { register, handleSubmit, errors } = useForm({
    mode: "onBlur",
    resolver: yupResolver(schema)
  });

  const [state, setState] = useState({
    wasSubmitted: false
  });

  const submit = async (data) => {
    window.alert(JSON.stringify(data));
  };

  if (state.wasSubmitted) {
    return <p>Congrats</p>;
  } else {
    return (
      <>
        <CssBaseline />
        <Container maxWidth="sm">
          <Typography variant="h2" component="h1">
            My form
          </Typography>
          <form noValidate autoComplete="off" onSubmit={handleSubmit(submit)}>
            <FormControl
              component="fieldset"
              error={!!errors.option}
            >
              <FormLabel component="legend">
                Please select the category or categories of books the child is
                interested in:
              </FormLabel>
              <FormGroup>
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option1"
                  label="Option 1"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option2"
                  label="Option 2"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  label="Option3"
                  value="Option 3"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option4"
                  label="Option 4"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option5"
                  label="Option 5"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option6"
                  label="Option 6"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option7"
                  label="Option 7"
                />
                <FormControlLabel
                  control={<Checkbox name="option" inputRef={register} />}
                  value="Option8"
                  label="Option 8"
                />
                <FormControlLabel
              <FormHelperText>Up to five categories</FormHelperText>
            </FormControl>

            <Button
              type="submit"
              disableElevation
            >
              Submit
            </Button>
          </form>
        </Container>
      </>
    );
  }
}

export default App;

Run Code Online (Sandbox Code Playgroud)

您还可以在此处找到项目的沙箱:

编辑现代共振-d7mpc

有任何想法吗?

Nea*_*arl 41

正如@aadlc所说,解决方案是将模式设置为onChangeall。我会解释原因。

来自react-hook-form API文档

mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'

姓名 类型 描述
提交时(默认) 细绳 验证将在事件上触发submit,无效输入将附加onChange事件侦听器以重新验证它们。
模糊 细绳 验证将在事件上触发blur
改变时 细绳 验证将在每个输入的事件上触发change,并导致多次重新渲染。警告:这通常会对性能产生重大影响。
触摸时 细绳 验证将在第一个事件时触发blur。之后,它将在每个change事件上触发。
全部 细绳 blur验证将在和事件上触发change

在您的代码中,表单模式是onBlur. 这意味着验证是在blur事件上触发的(取消输入焦点)。当您选择该选项时n+1,它会触发该选项的模糊事件n

例如,就在您选择第 6 个选项(无效)之前,blur事件从第 5 个选项(有效)触发,因为您不再关注它,并从选项 1-5 进行验证,因此您必须检查第 7 个选项以重新验证选项从 1 到 6。

-- select up to 5 options --
select option 4

blur event fires from option 4 -> validate -> pass
select option 5

blur event fires from option 5 -> validate -> pass
select option 6

blur event fires from option 6 -> validate -> fail
select option 7
Run Code Online (Sandbox Code Playgroud)

将验证模式更改为将在事件触发onChange验证,此时所有值都是最新的: change

-- select up to 5 options --
select option 4

blur event fires from option 4
select option 5
change event fires from option 5 -> validate -> pass

blur event fires from option 5
select option 6
change event fires from option 6 -> validate -> fail

blur event fires from option 6
select option 7
change event fires from option 7 -> validate -> fail
Run Code Online (Sandbox Code Playgroud)

将验证模式更改为all将同时验证 inblurchangeevents,这在此工作流程中可能有点过分,但它也有效。


小智 9

如果您使用受控组件,onBlur 可能不会自动触发。您必须手动连接它:

useController 文档
包装器文档

export const MyControlledField = ({ fieldName }: { fieldName: string }) => {
  const methods = useFormContext();
  const value = useWatch({ name: fieldName });
  const controller = useController({
    name: fieldName,
    control: methods.control,
  });
  return (
    <TextField
      value={value ?? ''}
      onChange={(e) => {
        methods.setValue(fieldName, e.target.value);
      }}
      onBlur={controller.field.onBlur}
    />
  );
};
Run Code Online (Sandbox Code Playgroud)

或者使用包装的组件:

export const MyWrappedField = ({ fieldName }: { fieldName: string }) => {
  const methods = useFormContext();

  return (
    <Controller
      control={methods.control}
      name={fieldName}
      render={({ field: { onChange, onBlur, value, name, ref }, fieldState, formState }) => (
        <TextField
          onBlur={onBlur}
          onChange={onChange}
          value={value}
          inputRef={ref}
        />
      )}
    />
  );
};
Run Code Online (Sandbox Code Playgroud)