Reputation: 399
I'm attempting to map over data I received from an API call. Getting shallow endpoints works fine, but anything nested gives me an error.
The goal is to get all of the opening themes and display them in a 'ul'.
The exact error "TypeError: anime.opening_themes is undefined"
Heres the endpoints.
Heres my component.
const AnimeDetails = (props) => {
const API = 'https://api.jikan.moe/v3/anime'
const initialState = {
anime: []
}
const [anime, setAnime] = useState(initialState)
useEffect(() => {
const getAnime = async () => {
const response = await fetch(`${API}/${props.match.params.animeId}`)
const data = await response.json()
console.log(data);
setAnime(data) // set initial state to hold data from our API call
}
getAnime()
}, []) // [] prevents useEffect from running in an infinite loop
return (
<AnimeDetailsWrapper>
<Title>{anime.title}</Title>
<Details>
{anime.opening_themes
.map((song, index) => (
<li key={index}>{song}</li>
))}
</Details>
</AnimeDetailsWrapper>
)
}
Upvotes: 2
Views: 1518
Reputation: 224
you should try like this
first, remove initialState code and use direct code like following
if the response is in the form of an array
const [anime, setAnime] = useState([])
if the response is in the form of an object
const [anime, setAnime] = useState({})
otherwise, null will work with any response
const [anime, setAnime] = useState(null)
return code like this
return (
<> {anime && <AnimeDetailsWrapper>
<Title>{anime.title}</Title>
<Details>
{anime.opening_themes
.map((song, index) => (
<li key={index}>{song}</li>
))}
</Details>
</AnimeDetailsWrapper>}</>
)
Upvotes: 0
Reputation: 62688
Your initial state is an empty array, not an empty object:
const initialState = {
anime: []
}
When your component mounts, there is no data yet, so you're attempting to render [].opening_themes.map
, and obviously there is no opening_themes
property on an empty array.
Set your initial state to an empty object instead:
const initialState = {}
And you will probably want to test that you have data before attempting to render it:
return anime.mal_id && (
<AnimeDetailsWrapper>
<Title>{anime.title}</Title>
<Details>
{anime.opening_themes
.map((song, index) => (
<li key={index}>{song}</li>
))}
</Details>
</AnimeDetailsWrapper>
)
This will prevent your component from rendering anything until your anime
state contains a mal_id
property.
Upvotes: 2
Reputation: 5667
The first time you render your component, the state anime
is equal to {anime: []}
, which has no property called opening_themes
.
Upvotes: 0