I am fetching data from an API which returns an array of objects in this format.
{Name: 'hitmonchan', Description: 'Fighting-type Pokémon introduced in Generation I'}
{Name: 'Gogoat', Description: 'A quadrupedal, hooved Pokémon similar to a goat'}... and so on
Here is what I am attempting to do. I fetch all the pokemons which is over 500, stuff them in an array called allPokemons
. Then I want to do stuff with 4 random pokemons from the list. So I will have an array called smallRandomPokemonArray
with only four pokemons chosen at random from the allPokemon
array.
import { useEffect, useState } from 'react';
import { getallPokemons } from '../services/pokemonapi';
const empty_pokemon = {
'Name': '',
'Description': ''
}
function PokemonComponent() {
const [allPokemons, setAllPokemons] = useState([]);
const [smallRandomPokemonArray, setSmallRandomPokemonArray] = useState([]);
useEffect(() => {
getAll();
}, []);
const getAll = () => {
getallPokemons()
.then(data => {
//actual data with over 500 objects show in log
console.log(data);
setAllPokemons(data);
randomChooser(data.length)
})
}
const randomChooser = (length) => {
let temporaryArray = [];
for (let i = 0; i < 4; i ) {
const randomIndex = Math.floor(Math.random() * length);
//First Problem: this is returning index in numbers followed by undefined... why?
console.log(randomIndex " " allPokemons[randomIndex]);
temporaryArray.push(allPokemons[randomIndex]);
//Second Problem: this is also returning "temp undefined"
console.log("temp " temporaryArray[i]);
}
setSmallRandomPokemonArray(temporaryArray);
}
return (
<>
<div className="pokemondiv">
{
smallRandomPokemonArray.map((element) => (
<div>
<p>{element.Name}</p>
<p>{element.Description}</p>
</div>
))
}
</div>
</>
)
}
export default PokemonComponent;
When I try to print values from the setSmallRandomPokemonArray
I get that error:
Uncaught TypeError: Cannot read properties of undefined (reading 'Name')
Also, please look at First problem and Second problem
part in the code. They are also appearing as undefined in the console.log. From my understanding, it should work because allPokemons
already exist when I start to randomize it. Then I just push four random values to the smallRandomPokemonArray
. I dont know why its throwing the error.
CodePudding user response:
The allPokemons
have not been set at the point where you are using it in randomChooser
. react will set all state after the function finished running.
You need to pass the data into randomChooser
.
const randomChooser = (data) => {
const length = data.length
let temporaryArray = [];
for (let i = 0; i < 4; i ) {
const randomIndex = Math.floor(Math.random() * length);
//First Problem: this is returning index in numbers followed by undefined... why?
console.log(randomIndex " " data[randomIndex]);
temporaryArray.push(data[randomIndex]);
//Second Problem: this is also returning "temp undefined"
console.log("temp " temporaryArray[i]);
}
setSmallRandomPokemonArray(temporaryArray);
}
CodePudding user response:
Problem
You are calling randomChooser(data.length)
just after setAllPokemons(data);
in getAll
function. At this point allPokemons
which is used inside randomChooser
is still []
.
emptyArray[0] = undefined. undefined.Name = Cannot read properties of undefined. The takeaway is that when you call a
setState
, the relatedstate
is updated asynchronously. A re-render is needed to have the update value.
Solution n° 1
Change getAll
to the code below, so its only job is to populate allPokemons
state:
const getAll = () => {
getallPokemons().then((data) => {
setAllPokemons(data);
});
};
Use an useEffect
to get the the four pokemons you need:
useEffect(() => {
if (allPokemons.length <= 0) return;
randomChooser(allPokemons.length);
}, [allPokemons, randomChooser]);
Solution n° 2
Change randomChooser
so that it receives the array, not its length:
const randomChooser = (allPokemons) => {
let temporaryArray = [];
for (let i = 0; i < 4; i ) {
const randomIndex = Math.floor(Math.random() * allPokemons.length);
temporaryArray.push(allPokemons[randomIndex]);
}
setSmallRandomPokemonArray(temporaryArray);
};
Change getAll
so you give data to randomChooser
:
const getAll = () => {
getallPokemons().then((data) => {
setAllPokemons(data);
randomChooser(data);
});
};