react-hook-form 在 handleSubmit 中处理服务器端错误

react-hook-form handling server-side errors in handleSubmit

我很难弄清楚如何处理不一定与 react-hook-form 中的单个输入字段相关的错误。 换句话说,我如何处理 handleSubmit 错误?

例如,具有以下形式:

import to from 'await-to-js'
import axios, { AxiosResponse } from 'axios'
import React from "react"
import { useForm } from "react-hook-form"

type LoginFormData = {
  username: string,
  password: string,
}

export const Login: React.FC = () => {
  const { register, handleSubmit } = useForm<LoginFormData>()

  const onSubmit = handleSubmit(async (data) => {
    const url = '/auth/local'

    const [err, userLoginResult] = await to<AxiosResponse>(axios.post(url, data))
    if (userLoginResult) {
      alert('Login successful')
    }
    else if (err) {
      alert('Bad username or password')
    }
  })

  return (
    <div className="RegisterOrLogIn">
      <form onSubmit={onSubmit}>
        <div>
          <label htmlFor="username">username</label>
          <input name="username" id="username" ref={register} />
        </div>
        <div>
          <label htmlFor="password">Password</label>
          <input type="password" id="password" name="password" ref={register} />
        </div>
        <button type="submit"> </button>
      </form>
    </div>
  )
}

是否有 react-hook-form 方式通知用户用户名或密码有误? 如,除了 alert()

也许这在别处有答案,但我没找到。


澄清 从服务器收到的错误不属于单个字段:

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": [
        {
            "messages": [
                {
                    "id": "Auth.form.error.invalid",
                    "message": "Identifier or password invalid."
                }
            ]
        }
    ],
    "data": [
        {
            "messages": [
                {
                    "id": "Auth.form.error.invalid",
                    "message": "Identifier or password invalid."
                }
            ]
        }
    ]
}

为了向您的用户显示服务器的错误,您需要使用:

  • setError 在服务器 returns 错误响应时以编程方式设置错误。
  • errors 获取表单中每个字段的错误状态以显示给用户。
type FormInputs = {
  username: string;
};

const { setError, formState: { errors } } = useForm<FormInputs>();

在您的 handleSubmit 回调中

axios
  .post(url, data)
  .then((response) => {
    alert("Login successful");
  })
  .catch((e) => {
    const errors = e.response.data;

    if (errors.username) {
      setError('username', {
        type: "server",
        message: 'Something went wrong with username',
      });
    }
    if (errors.password) {
      setError('password', {
        type: "server",
        message: 'Something went wrong with password',
      });
    }
  });

在你的组件中

<label htmlFor="username">username</label>
<input id="username" {...register("username")} />
<div>{errors.username && errors.username.message}</div>

现场演示

受@NearHuscarl 回答的启发,我做了以下 hack s.t。 usernamepassword 输入的更改将消除单个错误。

如果您的错误与表单中的多个字段相关,则此 hack 无法很好地扩展,但它适用于登录用例。

提交时:

const onSubmit = handleSubmit(async (data) => {
    const url = '/auth/local'

    const [err, userLoginResult] = await to<AxiosResponse>(axios.post(url, data)) // see await-to-js 
    if (userLoginResult) {
      alert('Login successful')
    }
    else if (err) {
      const formError = { type: "server", message: "Username or Password Incorrect" }
      // set same error in both:
      setError('password', formError)
      setError('username', formError)
    }
  })

组件:

  return (
    <div className="RegisterOrLogIn">
      <form onSubmit={onSubmit}>
        <div>
          <label htmlFor="username">username</label>
          <input name="username" id="username" ref={register} />
        </div>
        <div>
          <label htmlFor="password">Password</label>
          <input type="password" id="password" name="password" ref={register} />
        </div>
        <div>{errors.username && errors.password?.message /*note the cross check*/}</div>
        <button type="submit"> </button>
      </form>
    </div>
  )

通过在 errors.passworderrors.username 上设置和呈现错误,当用户更新这些字段中的任何一个时,错误将消失。