Reputation: 471
Im getting confused.. When I try to console.log(this.state.podcast[0].collectionId) Im getting an error saying: TypeError: Cannot read property 'collectionId' of undefined.
BUT! If I remove the console.log then everything is working fine..
Im in the learning process of understanding React JS. Can someone point in the right direction?
This is my component:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
export default class Podcast extends Component {
constructor(props) {
super(props);
this.state = {
podcast: []
};
}
// Fetches podID from props.match
fetchPodcast () {
const podcastID = this.props.match.params.podID
fetch(`https://itunes.apple.com/lookup?id=${podcastID}`)
.then(response => response.json())
.then(data => this.setState({
podcast: data.results
}));
}
componentDidMount () {
this.fetchPodcast()
}
render() {
console.log(this.state.podcast[0].collectionId)
return (
<div>
<h2> {this.props.match.params.podID}</h2>
<ul>
{this.state.podcast.map(podcast =>
<li key={podcast.collectionId}>
<Link to={`/podcast/${podcast.collectionId}`}>{podcast.collectionName}</Link>
</li>
)}
</ul>
</div>
)
}
}
Upvotes: 0
Views: 3593
Reputation: 8102
To see updated state, you can pass a callback to setState
as second argument:
fetch(`https://itunes.apple.com/lookup?id=${podcastID}`)
.then(response => response.json())
.then(data => this.setState({
podcast: data.results
},()=>{
console.log(this.state.podcast)
}));
and you can conditionally render your component like this:
render() {
const { podcast} = this.state;
return (
<div>
{podcast.length &&
<h2> {this.props.match.params.podID}</h2>
<ul>
{this.state.podcast.map(podcast =>
<li key={podcast.collectionId}>
<Link to={`/podcast/${podcast.collectionId}`}>{podcast.collectionName}</Link>
</li>
)}
</ul>
</h2> }
</div>
PS. make sure you're getting data in API response and Javascript is asynchronous. You render method will be called without waiting for the API response. Once you setState
anywhere your component will be re-rendered. It is showing podcast
as undefined on first render
Upvotes: 0
Reputation: 3303
Above image will give you a good idea about how React works, check when the render
phase happens.
So, if we relate this to your case, after constructor call render()
is called, as this.state.podcast
is an empty array, console.log
threw error while you tried to access non existing index value. Also map
function didn't execute as this.state.podcast
is an empty array.
Now after componentDidMount
, this.state.podcast
gets value, render
is called again and you get to see collection details.
Upvotes: 1
Reputation: 341
Your podcast list is empty when the render triggers. When an array is empty, Array.map
will effectively run through 0 elements, which is why it doesn't throw an error.
To console.log
this you could first check the first element exists by using console.log(this.state.podcast[0] && this.state.podcast[0].collectionId)
, or simply console.log(this.state.podcast[0])
which will render the whole object if it's defined.
Upvotes: 0
Reputation: 2289
When your component first renders your this.state.podcast
is empty, so your attempt to use it will show as undefined. The component re-renders when it receives an update on state and other props. So when your component initially loads, this.state.podcast
is undefined, but when it receives the podcast, it re-renders again, showing the values.
Upvotes: 0