I'm doing an exercise to learn React in which I have set up a page with a list of clickable pokemon names which are linking to the pokemons specific detail page. Below is the code of the details page
import { useState, useEffect } from "react";
import axios from "axios";
import { useParams } from "react-router-dom";
export default function DetailsPage() {
const pokeName = useParams();
console.log(pokeName);
const [pokeList, setPokeList] = useState([]);
useEffect(() => {
const fetchData = async () => {
const response = await axios.get(
"https://pokeapi.co/api/v2/pokemon?limit=151"
);
console.log(response.data);
setPokeList(response.data.results);
};
fetchData();
}, []);
const specificPokemon = pokeList.find((pokemon) => {
return pokemon.name === pokeName.pokemon_name;
});
console.log(specificPokemon);
console.log(specificPokemon.name);
return <div><p>{specificPokemon.name}</p></div>;
}
This code has an error I fail to understand
The console.log(specificPokemon)
works fine, but the console.log(specificPokemon.name)
gives me the following error
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
The correct code is the following, but I wonder why my method doesn't work
const [pokeList2, setPokeList2] = useState([]);
useEffect(() => {
const fetchData = async () => {
const response = await axios.get(
`https://pokeapi.co/api/v2/pokemon/${pokeName.pokemon_name}`
);
console.log(response.data);
setPokeList(response.data);
};
fetchData();
}, []);
console.log(pokeList);
Thank you
CodePudding user response:
When the code runs first the pokeList
is an empty array and it cannot find the property name
. You should create a second state and do something like this
const pokeName = useParams();
const [pokeList, setPokeList] = useState([]);
const [specificPokemon, setSpecificPokemon] = useState({});
useEffect(() => {
const fetchData = async () => {
const response = await axios.get(
"https://pokeapi.co/api/v2/pokemon?limit=151"
);
setPokeList(response.data.results);
const selectedPokemon = response.data.results.find((pokemon) => {
return pokemon.name === pokeName.pokemon_name;
});
setSpecificPokemon(selectedPokemon)
};
fetchData();
}, [])
And don't forget to make the specificPokemon property optional like this specificPokemon?.name
CodePudding user response:
When your component is mounted, pokeList is an empty array.
React will run the following block before the useEffect hook has finished running:
const specificPokemon = pokeList.find((pokemon) => {
return pokemon.name === pokeName.pokemon_name;
});
console.log(specificPokemon);
console.log(specificPokemon.name);
As long as your array is empty, specificPokemon
will be undefined
and calling specificPokemon.name
will trigger your error.
Beware with console.log
, its behavior is not always synchronous.
You might think specificPokemon
is properly defined because console.log
won't necessarily show undefined
.
To verify this, use console.log(JSON.stringify(specificPokemon));
.