
在构建现代Web应用时,表单验证是不可或缺的一环。react-hook-form结合yup提供了一种强大且高效的方式来处理客户端表单验证,例如检查字段是否为空、格式是否正确等。然而,对于需要与后端数据库交互才能确定的验证逻辑,例如用户登录时验证用户名和密码是否匹配,客户端验证工具如yup就力不从心了。这类验证必须在服务器端进行。
本文将指导您如何在保持yup客户端验证优势的同时,优雅地处理来自服务器端的登录凭证错误,并将其反馈给用户。
在登录场景中,yup可以确保用户名和密码字段不为空,但无法判断这对凭证是否真实存在于数据库中。这正是服务器端验证的职责。
原始代码中,yup的错误信息只在输入字段为空时显示。当用户输入了内容,但凭证不正确时,服务器会返回一个错误响应,但这个错误信息并没有被捕获并显示在UI上,导致用户体验不佳。我们需要一种机制来捕获fetch请求返回的服务器错误,并将其展示给用户。
最直接有效的方法是利用React的本地状态来存储服务器返回的错误信息。当表单提交后,在处理fetch请求的响应时,根据服务器返回的状态码或错误内容来更新这个状态,然后将错误信息渲染到UI上。
首先,在您的组件中引入一个状态变量来存储服务器端返回的错误信息。
import React, { useState } from "react";
// ... 其他导入
function Login(props) {
// ... 现有状态和钩子
const [submissionError, setSubmissionError] = useState(""); // 新增:用于存储服务器端提交错误
// ... 其他函数
const {
handleSubmit,
register,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
// ...
}在 formSubmit 函数中,我们需要检查 fetch 请求的响应状态。如果状态码表示失败(例如 400、401、500 等),则从响应中提取错误信息并更新 submissionError 状态。
const formSubmit = (data) => {
// 每次提交前清除之前的错误信息
setSubmissionError("");
fetch("http://localhost:3001/login", {
method: "POST",
body: JSON.stringify({ username: data.username, password: data.password }),
headers: { "Content-Type": "application/json" },
})
.then(async (response) => { // 注意这里使用了 async/await 或者 .then(async (response) => ...)
if (response.status === 200) {
props.router.navigate("/");
setIsLoggedIn(true);
} else {
// 处理非200状态码的响应
if (response.headers.get("Content-Type")?.includes("application/json")) {
const errorData = await response.json();
// 假设服务器返回的错误结构是 { error: "错误消息" }
setSubmissionError(errorData.error || "登录失败,请检查您的凭证。");
} else {
// 如果服务器没有返回JSON格式的错误,根据状态码给出通用提示
if (response.status === 401) {
setSubmissionError("用户名或密码不正确。");
} else if (response.status === 400) {
setSubmissionError("请求无效,请检查输入。");
} else {
setSubmissionError("服务器发生错误,请稍后再试。");
}
}
console.log("登录失败,状态码:", response.status);
}
})
.catch((error) => {
console.error("网络请求错误:", error);
setSubmissionError("网络连接失败,请检查您的网络。");
});
};注意事项:
最后,在您的JSX中,条件性地渲染 submissionError 状态。通常,这些错误会显示在表单的顶部或相关输入字段的下方。
return (
<div className="sign-up">
<h1>Log in</h1>
<form onSubmit={handleSubmit(formSubmit)}>
{/* 在表单顶部显示提交错误 */}
{submissionError && <p className="error-message">{submissionError}</p>}
<Input
id="username"
value={username}
onChange={onUsernameChange}
label="Username"
type="text"
placeholder="Enter Username"
register={{ ...register("username") }}
errorMessage={errors.username?.message}
/>
<Input
id="password"
value={password}
onChange={onPasswordChange}
label="Password"
type="password"
placeholder="Enter Password"
register={{ ...register("password") }}
errorMessage={errors.password?.message}
/>
<button>Log in</button>
</form>
<button className="button-link" onClick={() => props.onFormSwitch("signup")}>
Don't have an account? Register here.
</button>
</div>
);您可以为 .error-message 类添加一些CSS样式,使其更醒目。
import React, { useState } from "react";
import Input from "./Input"; // 假设这是您的自定义Input组件
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import useAuth from "../Components/Zustand - Auth/authLogin"; // 假设这是您的认证状态管理
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return (
<Component
{...props}
router={{ location, navigate, params }}
/>
);
}
return ComponentWithRouterProp;
}
const schema = yup.object({
username: yup.string().required("用户名是必填项"),
password: yup.string().required("密码是必填项"), // 这里的yup验证只做必填项检查
}).required();
function Login(props) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [submissionError, setSubmissionError] = useState(""); // 新增:用于存储服务器端提交错误
const { setIsLoggedIn } = useAuth(); // 从Zustand获取设置登录状态的函数
const onUsernameChange = (event) => {
setUsername(event.target.value);
};
const onPasswordChange = (event) => {
setPassword(event.target.value);
};
const {
handleSubmit,
register,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
const formSubmit = async (data) => { // 使用async函数处理异步操作
setSubmissionError(""); // 每次提交前清除之前的错误信息
try {
const response = await fetch("http://localhost:3001/login", {
method: "POST",
body: JSON.stringify({ username: data.username, password: data.password }),
headers: { "Content-Type": "application/json" },
});
if (response.status === 200) {
props.router.navigate("/");
setIsLoggedIn(true);
} else {
// 尝试解析JSON错误信息
if (response.headers.get("Content-Type")?.includes("application/json")) {
const errorData = await response.json();
// 假设服务器返回 { message: "错误消息" } 或 { error: "错误消息" }
setSubmissionError(errorData.message || errorData.error || "登录失败,请检查您的凭证。");
} else {
// 如果不是JSON,根据状态码提供通用错误
if (response.status === 401 || response.status === 400) {
setSubmissionError("用户名或密码不正确。");
} else if (response.status === 500) {
setSubmissionError("服务器内部错误,请稍后再试。");
} else {
setSubmissionError("登录失败,发生未知错误。");
}
}
console.log("登录失败,状态码:", response.status);
}
} catch (error) {
console.error("网络请求错误:", error);
setSubmissionError("网络连接失败,请检查您的网络或稍后再试。");
}
};
return (
<div className="sign-up">
<h1>登录</h1>
<form onSubmit={handleSubmit(formSubmit)}>
{/* 在表单顶部显示服务器端提交错误 */}
{submissionError && <p className="error-message" style={{ color: 'red', marginBottom: '10px' }}>{submissionError}</p>}
<Input
id="username"
value={username}
onChange={onUsernameChange}
label="用户名"
type="text"
placeholder="输入用户名"
register={{ ...register("username") }}
errorMessage={errors.username?.message}
/>
<Input
id="password"
value={password}
onChange={onPasswordChange}
label="密码"
type="password"
placeholder="输入密码"
register={{ ...register("password") }}
errorMessage={errors.password?.message}
/>
<button type="submit">登录</button>
</form>
<button className="button-link" onClick={() => props.onFormSwitch("signup")}>
没有账号?点击注册。
</button>
</div>
);
}
export default withRouter(Login);通过将客户端验证(由react-hook-form和yup处理)与服务器端验证(通过React状态管理fetch响应)结合起来,我们可以为用户提供一个既能快速响应基本输入错误,又能准确反馈复杂业务逻辑错误(如凭证不匹配)的健壮表单。这种分层验证策略是构建安全、用户友好型Web应用的关键。记住,永远不要将敏感的业务逻辑验证完全放在客户端,服务器端验证是您的最后一道防线。
以上就是React表单结合Yup进行客户端与服务器端验证:处理登录凭证错误的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号