javascript - 对象数组在 React 中未完全渲染,并在控制台上显示与实际不匹配的数组长度
问题描述
我在 React 中渲染一组对象时遇到问题。出于某种原因,在它拥有的 5 个元素中,它只呈现 3 个。我在控制台中检查了它,以下显示:
出于某种原因,最初在控制台上显示该数组有 3 个元素,但如果我在控制台中检查它,则有 5 个元素而不是 3 个。准确地说,呈现的元素是前 3 个。这是 React 组件,以防万一它可能会有所帮助:
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import './RegisterBlock.css';
const RegisterBlock = () => {
const [gamertag, setGamerTag] = useState("");
const [password, setPassword] = useState("");
const [repassword, setRepassword] = useState("");
const [mail, setMail] = useState("");
const [isChecked, setIsChecked] = useState(false);
const [errors, setErrors] = useState(null);
const handleChange = (event) => {
event.target.name === "password" ? setPassword(event.target.value) :
event.target.name === "repassword" ? setRepassword(event.target.value) :
event.target.name === "gamertag" ? setGamerTag(event.target.value) :
event.target.name === "email" ? setMail(event.target.value) : setIsChecked(!isChecked) ;
}
const handleSubmit = (event) => {
event.preventDefault();
var totalErrors = [];
if (gamertag.length === 0 || gamertag.length > 30) {
totalErrors.push({"error": "La contraseña debe tener entre 2 y 30 caracteres"});
}
if (!/^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[A-Za-z]+$/.test(mail)) {
totalErrors.push({"error": "Introduce un correo válido"});
}
if (!isChecked) {
totalErrors.push({"error": "Debes aceptar haber leído las políticas para poder registrarte"});
}
const url = "URL API" + mail;
fetch(url)
.then(response => response.json())
.then(data => {
data.length > 0 && totalErrors.push({"error": "Ya hay una cuenta con este correo"});
});
const urlGamertag = "URL API" + gamertag;
fetch(urlGamertag)
.then(response => response.json())
.then(data => {
data.length > 0 && totalErrors.push({"error": "El gamertag ya ha sido usado por otro usuario"});
});
setErrors(totalErrors);
}
useEffect(() => {
if (errors?.length === 0) {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: gamertag,
password: password,
email: mail
})
};
fetch('URL API', requestOptions)
.then(response => response.json())
}
}, [errors?.length === 0])
return (
<div className="login-block">
<div className="wrapper">
<form onSubmit={handleSubmit} method="post">
<input type="text" placeholder="Gamertag" name="gamertag" value={gamertag} onChange={handleChange}/>
<input type="mail" placeholder="Email" name="email" value={mail} onChange={handleChange}/>
<input type="password" placeholder="Contraseña" name="password" value={password} onChange={handleChange}/>
<input type="password" placeholder="Verifica contraseña" name="repassword" value={repassword} onChange={handleChange}/>
<div className="form__checkbox">
<input onChange={handleChange} name="policy" id="policy" type="checkbox" checked={isChecked} />
<label htmlFor="policy">Al registrarte confirmas haber leído la <Link to="/politica-de-privacidad">Política de privacidad</Link> y Aviso legal.</label>
</div>
{console.log(errors)}
{
errors?.length > 0 && (
<ul className="form--errors">
{
errors.map((item, index) => {
return <li key={index}>{item.error}</li>
})
}
</ul>
)
}
<input type="submit" value="Registrarse"/>
</form>
</div>
</div>
)
}
export default RegisterBlock;
解决方案
您的前 3 个验证是同步的,因此它们会立即添加到数组中并呈现。然而,最后 2 个在服务器端进行验证,这需要一些时间。当响应到达时,渲染过程已经完成。尽管错误被添加到数组中,但对数组本身的引用保持不变,因此 React 不会接收更改。所以这里有 2 个选项:setErrors
在每个响应上使用克隆数组,或者在渲染任何内容之前等待所有验证完成。第一个会导致冲洗,所以在这种情况下最好等待fetch
. 请注意,您有 2 个请求,可能可以同时发出,因此可能值得将它们包装成Promise.all
. 顺序选项(一次一个验证):
await fetch(url)
...
await fetch(urlGamertag)
setErrors(totalErrors);
同时触发两个请求:
const firstPromise = fetch(url)
...
const secondPromise =fetch(urlGamertag)
...
await Promise.all([firstPromice , secondPromise ])
setErrors(totalErrors);