reactjs React-钩状:使用onBlur模式时验证不起作用

u91tlkcl  于 2023-01-08  发布在  React
关注(0)|答案(2)|浏览(311)

当用户选择超过5个复选框但未成功时,我尝试显示yupreact-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;

您也可以在这里找到项目的沙盒:

有什么想法吗?

o2gm4chl

o2gm4chl1#

正如@aadlc所说,解决方法是将模式设置为onChangeall,我将解释原因。
来自React钩型API docs
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
| 姓名|类型|说明|
| - ------|- ------|- ------|
| onSubmit(默认)|弦|验证将在submit事件上触发,无效输入将附加onChange事件侦听器以重新验证它们。|
| 模糊|弦|验证将在blur事件上触发。|
| | | |
| 更改时|弦|验证将在每个输入的change事件上触发,并导致多次重新呈现。警告:这通常伴随着对性能的显著影响。|
| | | |
| 接触|弦|验证将在第一个blur事件上触发。之后,它将在每个change事件上触发。|
| 全部|弦|验证将在blurchange事件上触发。|
在您的代码中,表单模式是onBlur。这意味着验证是在blur事件(不聚焦输入)上触发的。当您选择选项n+1时,它会从选项n触发blur事件。
例如,就在您选择第6个选项(无效)之前,x1m1 - 5n1x事件从第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将在blurchange事件中进行验证,这在此工作流中可能有些过头,但它仍然有效。

31moq8wy

31moq8wy2#

如果你使用的是受控组件,onBlur可能不会自动触发。你必须手动连接它:
useController docs
wrapper docs

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}
    />
  );
};

或者使用 Package 组件:

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}
        />
      )}
    />
  );
};

相关问题