React useState 钩子:对象 属性 保持不变
React useState hook: object property remains unchanged
我最近开始学习 React,我有一个有登录表单的组件:
import Joi from "joi";
import { useState } from "react";
const Login = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const loginSchema = Joi.object().keys({
username: Joi.string().required(),
password: Joi.string().required(),
});
const [errors, setErrors] = useState({ username: null, password: null });
const handleSubmit = (form) => {
form.preventDefault();
validate();
};
const validate = () => {
const { error } = loginSchema.validate(
{ username, password },
{ abortEarly: false }
);
if (!error) return null;
for (const item of error.details) {
let key = item.path[0];
let value = item.message;
setErrors({ ...errors, [key]: value });
}
return errors;
};
return (
<div className="container">
<div>
<h1>Login</h1>
</div>
<div className="card">
<div className="card-body">
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="username">Username</label>
<input
name="username"
type="text"
className="form-control"
id="username"
placeholder="Enter username"
value={username}
onChange={(username) => setUsername(username.target.value)}
/>
{errors.username && (
<div className="alert alert-danger">{errors.username}</div>
)}
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
name="password"
type="password"
className="form-control"
id="password"
placeholder="Password"
value={password}
onChange={(password) => setPassword(password.target.value)}
/>
{errors.password && (
<div className="alert alert-danger">{errors.password}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
{/* Delete later */}
<h4>{JSON.stringify(errors)}</h4>
</div>
</div>
</div>
);
};
export default Login;
在这里,我试图在错误对象中设置用户名和密码的值,但由于某种原因,只设置了密码 属性,用户名 属性 仍然为空。我已经使用了对象解构,但它仍然没有设置值,请帮助。
我认为问题来自这段代码
for (const item of error.details) {
let key = item.path[0];
let value = item.message;
setErrors({ ...errors, [key]: value });
}
此处您在 for 循环中使用相同的 errors
对象调用 setErrors
,因此仅考虑最后一个字段。
这是一个可能的解决方案:
if (!error) return null;
const newErrors = error.details.reduce((acc, item) => {
const key = item.path[0];
const value = item.message;
acc[key] = value;
return acc;
}, {...errors});
setErrors(newErrors);
状态更新不会立即反映在 React 中,并且由于您遍历数据以多次设置错误对象,由于事件处理程序中的批处理以及状态更新受到影响的事实,它仅在最后一个键中设置通过闭包。
您应该改为创建更新的对象并将其设置为状态一次
let newErrors = {};
for (const item of error.details) {
let key = item.path[0];
let value = item.message;
newErrors = { ...newErrors, [key]: value };
}
setErrors(prev => ({...prev, ...newErrors}));
我最近开始学习 React,我有一个有登录表单的组件:
import Joi from "joi";
import { useState } from "react";
const Login = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const loginSchema = Joi.object().keys({
username: Joi.string().required(),
password: Joi.string().required(),
});
const [errors, setErrors] = useState({ username: null, password: null });
const handleSubmit = (form) => {
form.preventDefault();
validate();
};
const validate = () => {
const { error } = loginSchema.validate(
{ username, password },
{ abortEarly: false }
);
if (!error) return null;
for (const item of error.details) {
let key = item.path[0];
let value = item.message;
setErrors({ ...errors, [key]: value });
}
return errors;
};
return (
<div className="container">
<div>
<h1>Login</h1>
</div>
<div className="card">
<div className="card-body">
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="username">Username</label>
<input
name="username"
type="text"
className="form-control"
id="username"
placeholder="Enter username"
value={username}
onChange={(username) => setUsername(username.target.value)}
/>
{errors.username && (
<div className="alert alert-danger">{errors.username}</div>
)}
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
name="password"
type="password"
className="form-control"
id="password"
placeholder="Password"
value={password}
onChange={(password) => setPassword(password.target.value)}
/>
{errors.password && (
<div className="alert alert-danger">{errors.password}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
{/* Delete later */}
<h4>{JSON.stringify(errors)}</h4>
</div>
</div>
</div>
);
};
export default Login;
在这里,我试图在错误对象中设置用户名和密码的值,但由于某种原因,只设置了密码 属性,用户名 属性 仍然为空。我已经使用了对象解构,但它仍然没有设置值,请帮助。
我认为问题来自这段代码
for (const item of error.details) {
let key = item.path[0];
let value = item.message;
setErrors({ ...errors, [key]: value });
}
此处您在 for 循环中使用相同的 errors
对象调用 setErrors
,因此仅考虑最后一个字段。
这是一个可能的解决方案:
if (!error) return null;
const newErrors = error.details.reduce((acc, item) => {
const key = item.path[0];
const value = item.message;
acc[key] = value;
return acc;
}, {...errors});
setErrors(newErrors);
状态更新不会立即反映在 React 中,并且由于您遍历数据以多次设置错误对象,由于事件处理程序中的批处理以及状态更新受到影响的事实,它仅在最后一个键中设置通过闭包。
您应该改为创建更新的对象并将其设置为状态一次
let newErrors = {};
for (const item of error.details) {
let key = item.path[0];
let value = item.message;
newErrors = { ...newErrors, [key]: value };
}
setErrors(prev => ({...prev, ...newErrors}));