Javascript 对象数组在React中未完全渲染,并在控制台上显示与实际不匹配的数组长度

Javascript 对象数组在React中未完全渲染,并在控制台上显示与实际不匹配的数组长度,javascript,reactjs,object,Javascript,Reactjs,Object,我在React中渲染对象阵列时遇到问题。出于某种原因,在它拥有的5个元素中,它只渲染了3个。我已经在控制台中进行了检查,如下所示: 出于某种原因,最初在控制台上显示该数组有3个元素,但如果我在控制台中检查它,则有5个元素而不是3个。渲染的元素正好是前3个元素。这是React组件,以防有帮助: import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import '

我在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;
import React,{useffect,useState}来自“React”;
从'react router dom'导入{Link};
导入“./RegisterBlock.css”;
常量寄存器块=()=>{
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);
常量handleChange=(事件)=>{
event.target.name==“密码”?设置密码(event.target.value):
event.target.name==“repassword”?设置repassword(event.target.value):
event.target.name==“gamertag”?setGamerTag(event.target.value):
event.target.name==“email”?setMail(event.target.value):setIsChecked(!isChecked);
}
const handleSubmit=(事件)=>{
event.preventDefault();
var totalErrors=[];
如果(gamertag.length==0 | | gamertag.length>30){
totalErrors.push({“error”:“La contraseña debe tener entre 2 y 30克拉”});
}
如果(!/^[a-zA-Z0-9]+@[a-zA-Z0-9]+\[a-zA-z]+$/.测试(邮件)){
推送({“错误”:“引入联合国科雷奥·瓦利多”});
}
如果(!已检查){
推送({“error”:“Debes aceptar haber leído las políticas para poder registerte”});
}
const url=“url API”+邮件;
获取(url)
.then(response=>response.json())
。然后(数据=>{
data.length>0&&totalErrors.push({“error”:“Ya hay una cuenta con este correo”});
});
const urlGamertag=“URL API”+gamertag;
获取(urlGamertag)
.then(response=>response.json())
。然后(数据=>{
data.length>0&&totalErrors.push({“error”:“El gamertag ya ha sido usado por otro usuario”});
});
设置错误(总错误);
}
useffect(()=>{
如果(错误?.length==0){
常量请求选项={
方法:“POST”,
标题:{'Content-Type':'application/json'},
正文:JSON.stringify({
姓名:gamertag,,
密码:密码,
电邮:电邮
})
};
获取('URL API',请求选项)
.then(response=>response.json())
}  
},[errors?.length==0])
返回(
Al Registrate confirmas haber leído la Política de privacidad y Aviso leído la Política de privacidad y leído la Aviso legal。
{console.log(错误)}
{
错误?长度>0&&(
    { 错误。映射((项目,索引)=>{ 返回
  • {item.error}
  • }) }
) } ) } 导出默认注册表锁;
前3次验证是同步的,因此它们会立即添加到数组中并呈现。然而,最后2个是在服务器端验证的,这需要一些时间。当响应到达时,渲染过程完成。虽然错误已添加到数组中,但对数组本身的引用保持不变,因此React不会接受更改。因此这里有两个选项:要么使用克隆数组对每个响应执行
setErrors
,要么等待所有验证完成,然后再呈现任何内容。第一个将导致刷新,因此在这种情况下,最好等待
fetch
。请注意,您有两个请求,它们可能可以同时发出,因此将它们包装成
Promise.all
。顺序选项(一次一个验证):

同时触发两个请求:

const firstPromise = fetch(url)
...
const secondPromise =fetch(urlGamertag)
...
await Promise.all([firstPromice , secondPromise ])
setErrors(totalErrors);

您没有等待响应,因此当它们到达时,组件被渲染,它们只是被推到同一个数组中而没有反应。添加
wait
fetch
@NadiaChibrikova哇,就是这样!非常感谢你!您能否将解决方案添加为答案,以便我验证它?完成(还添加了您可能希望使用的其他内容:)
const firstPromise = fetch(url)
...
const secondPromise =fetch(urlGamertag)
...
await Promise.all([firstPromice , secondPromise ])
setErrors(totalErrors);