Reputation: 25
I am trying to load JSON data via a call in the constructor and then pass that data to a series of child elements. The problem is that all the data seems to load except for one item (picture.url
). All the other info loads and displays properly, but I get an error when trying to load the picture value - it is a nested JSON object with two fields, comment
and url
.
Here is an example of a normal JSON response:
{
"id": 001,
"name": "Harry",
"online_status": "OFFLINE",
"picture": {
"comment": SOMECOMMENT,
"url": SOMEURL
},
"last_login": SOMEDATEOBJECT,
}
And here is my code:
TilesContainer.js - where the fetch call is made
class TilesContainer extends Component {
constructor(props){
super(props);
this.state = { users: [], };
this.getUsers = this.getUsers.bind(this);
this.tiles = this.tiles.bind(this);
this.getUsers("http://localhost:3000/api/search?length=32");
}
getUsers(usersLink) {
fetch(usersLink)
.then(response => response.json())
.then(myJson => {
let users = myJson.items;
this.setState({
users: users,
})
})
}
tiles() {
return (
this.state.users.map(user => (
<Tile key={user.id} id={user.id} name={user.name} lastLogin={user.last_login}
onlineStatus={user.online_status} pictureLink={user.picture.url} />
))
)
}
render(){
return (
<div id="tiles-container"
className="tiles-container">
{this.tiles()}
</div>
)
}
}
export default TilesContainer
Tiles.js - where the data is passed as props
class Tile extends Component {
render() {
let lastLoginDisplay = "";
let lastLogin = Date.parse(this.props.lastLogin);
let now = new Date();
let timeDifferenceInMs = now.getTime() - lastLogin;
let timeDifferenceInHours = Math.floor(timeDifferenceInMs / (1000 * 60 * 60));
let timeDifferenceInDays = Math.floor(timeDifferenceInMs / (1000 * 60 * 60 * 24));
if (this.props.onlineStatus === "OFFLINE") {
if (timeDifferenceInHours <= 24 ) {
if (timeDifferenceInHours === 1) {
lastLoginDisplay = "Last seen " + timeDifferenceInHours.toString() + " hour ago";
} else {
lastLoginDisplay = "Last seen " + timeDifferenceInHours.toString() + " hours ago";
}
} else {
if (timeDifferenceInDays === 1) {
lastLoginDisplay = "Last seen " + timeDifferenceInDays.toString() + " day ago";
} else {
lastLoginDisplay = "Last seen " + timeDifferenceInDays.toString() + " days ago";
}
}
} else {
lastLoginDisplay = this.props.onlineStatus;
}
return (
<div id={this.props.id} className='tile'>
<h2>{this.props.name}</h2>
<img src={this.props.pictureLink} alt={"userPic"}/>
<h3><span>{lastLoginDisplay}</span></h3>
</div>
)
}
}
export default Tile
And here is a screenshot of the error message I get when it fails to load:
Granted, when I tried passing the whole user object as one prop and then console.logging the url, I was able to! It would output a whole list of URLs and then it would produce the same error...Not sure if this is about how I'm trying to load the data (i.e. the problem is asynchronous). Like I said, all the other data fields load and are successfully passed as props, it's only the picture field giving this trouble. Thanks.
EDIT: Output of the debugger showing me that one of the items in user data array was missing the picture
field, thus it was coming up undefined.
Upvotes: 0
Views: 468
Reputation: 3034
Are you confident that the value of picture is not actually undefined in one of your API responses?
Your mapping function seems to recieve a User object just fine - it can resolve user.name and user.offline_status, for example (I am fairly sure these will be evaluated in left-right order as JSX props). You aren't merging objects or doing any strange mutations. So the most obvious possibility is that, as the error message says, user.picture really IS undefined.
The easiest way to check is to open the network tab in your device tools and inspect the JSON payload that comes back from the server. I strongly suspect that a field you thought was guaranteed is actually optional.
EDIT
If you need to debug the tiles mapping function, try
tiles() {
return (
this.state.users.map(user => {
debugger;
return <Tile key={user.id} id={user.id} name={user.name} lastLogin={user.last_login}
onlineStatus={user.online_status} pictureLink={user.picture.url} />
});
}
(Sorry, it is very hard to type out code on a phone)
Upvotes: 1