react-hook-form 自定义解析器仅在提交后检查

react-hook-form custom resolver only checking after submit

我正在构建一个带有 react-hook-form 的抽象表单组件,是的,用于验证。表单有效,验证有效,但只有在按下提交按钮之后。

它在 codesandbox,但是...

import React, { cloneElement } from "react";
import "./styles.css";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { string as yupString, object as yupObject } from "yup";
import {
  Box,
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  TextField
} from "@mui/material";

let renderCount = 0;

export const FormContent = ({ content }) => {
  return content.map((item, i) => {
    const name = item.component.props.name;

    return (
      <Controller
        key={name + "_" + i}
        name={name}
        defaultValue=""
        render={({ field, fieldState: { error }, formState: { isDirty } }) => {
          return cloneElement(item.component, {
            ...field,
            error: isDirty && !!error,
            helperText: isDirty && error?.message,
            FormHelperTextProps: { error: true }
          });
        }}
      />
    );
  });
};

export default function App() {
  renderCount++;

  const usernameInput = {
    validation: yupString().required("Username is required"),
    component: (
      <TextField required label="Username" name="username" type="text" />
    )
  };

  const passwordInput = {
    validation: yupString().required("Password is required"),
    component: <TextField required label="Password" name="password" />
  };

  const content = [usernameInput, passwordInput];

  let validationSchema = yupObject().shape({});

  // construct schema
  content.forEach((item) => {
    validationSchema = validationSchema.concat(
      yupObject().shape({
        [item.component.props.name]: item.validation
      })
    );
  });

  const methods = useForm({
    resolver: yupResolver(validationSchema)
  });

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

  return (
    <Dialog open>
      <Box>Render Count: {renderCount}</Box>

      <FormProvider {...methods}>
        <Box component="form" onSubmit={methods.handleSubmit(onFormSubmit)}>
          <DialogContent>
            <FormContent content={content} />
          </DialogContent>
          <DialogActions>
            <Button
              type="submit"
              fullWidth
              name="login"
              variant="contained"
              color="primary"
              size="large"
            >
              Login
            </Button>
          </DialogActions>
        </Box>
      </FormProvider>
    </Dialog>
  );
}

如果您在字段中键入一些数据,然后在不按下按钮的情况下删除数据,则不会发生任何事情。如果您将字段留空并按下按钮,它会给出必需的本机组件错误消息(即,它不会执行 Yup 解析)。但是,如果您输入一些数据,按下按钮,然后擦除数据,然后 Yup 验证开始。如何在按下按钮之前让它工作?

您需要从输入组件中删除 required 属性,否则本机 html 验证将启动。

如果您想在按下提交按钮之前开始验证,您需要使用其他一些 mode 作为表单,例如:

  const methods = useForm({
    resolver: yupResolver(validationSchema),
    mode: 'onChange' // or 'onBlur' for example
  });

Codesandbox

More info in the docs