Reputation: 250
I am having problem rendering an arrray of objects in React. For some reason, of 5 elements that it has, it only renders 3. I have checked it in the console, and the following shows:
For some reason, initially it appears on console that the array has 3 elements, but if I check it in the console there are 5 elements instead of 3. Precisely the elements that are rendered are the first 3. This is the React component in case it could be of help:
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;
Upvotes: 0
Views: 514
Reputation: 5036
Your first 3 validation are synchronous, so they're immediately added to the array and rendered. The last 2 however are validated on the server side, which takes a bit of time. By the time the response arrives the rendering process is finished. Although the errors are added to the array, the reference to the array itself stays the same, so React doesn't pick up the change. So there are 2 options here: either setErrors
on each response with a cloned array or wait for all validations to finish before rendering anything. The first would result in flushing, so in this case it's better to wait for fetch
. Note that you have 2 request, which probably can made at the same time, so it might worth to wrap them into Promise.all
. Sequential option (one validation at a time):
await fetch(url)
...
await fetch(urlGamertag)
setErrors(totalErrors);
Firing both request at the same time:
const firstPromise = fetch(url)
...
const secondPromise =fetch(urlGamertag)
...
await Promise.all([firstPromice , secondPromise ])
setErrors(totalErrors);
Upvotes: 1