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

问题描述 投票:0回答:2

当用户选择超过 5 个复选框但未成功时,我尝试使用

yup
react-hook-form
显示错误。

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

这是简化的代码:

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;

您还可以在这里找到该项目的沙箱:

Edit modern-resonance-d7mpc

有什么想法吗?

reactjs material-ui yup react-hook-form
2个回答
48
投票

正如@aadlc所说,解决方案是将模式设置为

onChange
all
。我会解释原因。

来自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

将验证模式更改为

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
将验证模式更改为 

all

 将在 
blur
change
 事件中进行验证,这在此工作流程中可能有点过分,但它也有效。


12
投票
如果您使用受控组件,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} /> ); };
或者使用包装组件:

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} /> )} /> ); };
    
© www.soinside.com 2019 - 2024. All rights reserved.