Reputation: 71
I'm trying to create a pokemon search app using the pokemon api here - https://pokeapi.co/ I am getting an error of "Cannot read property 'species' of undefined". Is this where I should be using useEffect? I am guessing that it has to do with me not using an async / await functionality but I wanted to ask if maybe it's something else first.
Here is my code
import { useState, useEffect } from "react";
import "./App.css";
function App() {
const [pokemonName, setPokemonName] = useState("ditto");
const [chosen, setChosen] = useState(false);
const [pokemonData, setPokemonData] = useState({
name: "",
species: "",
img: "",
hp: "",
attack: "",
defense: "",
type: "",
});
const searchPokemon = () => {
const response = fetch(
`https://pokeapi.co/api/v2/pokemon/${pokemonName}`
).then((response) => {
setPokemonData({
name: pokemonName,
species: response.data.species.name,
img: response.data.sprites.front_default,
hp: response.data.stats[0].base.stat,
attack: response.data.stats[1].base.stat,
defense: response.data.stats[3].base.stat,
type: response.data.types[0].type.name,
});
setChosen(true);
});
console.log(response);
};
return (
<div className="App">
<input
className="border-b-2 border-black px-4"
type="text"
onChange={(e) => {
setPokemonName(e.target.value);
}}
/>
<button
className="rounded text-white bg-blue-500 p-2 text-sm"
onClick={searchPokemon}
>
Search Pokemon
</button>
<div>
{!chosen ? (
<h1>Please choose a pokemon</h1>
) : (
<>
<h1>{pokemonData.name}</h1>
<img src={pokemonData.img} alt={pokemonData.name} />
<h2>{pokemonData.species}</h2>
<h2>{pokemonData.type}</h2>
<h2>{pokemonData.hp}</h2>
<h2>{pokemonData.attack}</h2>
<h2>{pokemonData.defense}</h2>
</>
)}
</div>
</div>
);
}
export default App;
Upvotes: 1
Views: 4090
Reputation: 11
Try creating a function to fetch the data from the API. Something like this
function getPokemonData() {
fetch('https://pokeapi.co/api/v2/pokemon/')
.then((response) => response.json())
.then((response) =>
setPokemonData({
name: pokemonName,
species: response.data.species.name,
img: response.data.sprites.front_default,
hp: response.data.stats[0].base.stat,
attack: response.data.stats[1].base.stat,
defense: response.data.stats[3].base.stat,
type: response.data.types[0].type.name,
})
);
}
And then call this function inside componentDidMount
componentDidMount(){
this.getPokemonData();
}
Upvotes: 1
Reputation: 192607
You don't convert the response to .json()
, and you also add .data
when parsing response, which is not needed. In addition, you base.stat
should be base_state
.
const { useState, useEffect } = React;
function App() {
const [pokemonName, setPokemonName] = useState("ditto");
const [chosen, setChosen] = useState(false);
const [pokemonData, setPokemonData] = useState({
name: "",
species: "",
img: "",
hp: "",
attack: "",
defense: "",
type: "",
});
const searchPokemon = () => {
const response = fetch(
`https://pokeapi.co/api/v2/pokemon/${pokemonName}`
)
.then(response => response.json())
.then(response => {
setPokemonData({
name: pokemonName,
species: response.species.name,
img: response.sprites.front_default,
hp: response.stats[0].base_stat,
attack: response.stats[1].base_stat,
defense: response.stats[3].base_stat,
type: response.types[0].type.name,
});
setChosen(true);
});
};
return (
<div className="App">
<input
className="border-b-2 border-black px-4"
type="text"
onChange={(e) => {
setPokemonName(e.target.value);
}}
/>
<button
className="rounded text-white bg-blue-500 p-2 text-sm"
onClick={searchPokemon}
>
Search Pokemon
</button>
<div>
{!chosen ? (
<h1>Please choose a pokemon</h1>
) : (
<React.Fragment>
<h1>{pokemonData.name}</h1>
<img src={pokemonData.img} alt={pokemonData.name} />
<h2>{pokemonData.species}</h2>
<h2>{pokemonData.type}</h2>
<h2>{pokemonData.hp}</h2>
<h2>{pokemonData.attack}</h2>
<h2>{pokemonData.defense}</h2>
</React.Fragment>
)}
</div>
</div>
);
}
ReactDOM.render(
<App />,
root
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 5101
you forgot to do response.json() after the fetch, to get the body in json format, and you have a few errors in the data shape (the response is not under a "data" attribute)
see here a modified working version: https://codesandbox.io/s/keen-brook-8egfe?file=/src/App.js
Upvotes: 1