Reputation: 21
I try solve my problem and can't handle that. I created API using Express JS and I want to display(map) my state array. In componentDidMount() I update listOfUsers[] and console.log return proper data. When I want map my array in render() it return some errors:
Uncaught (in promise) TypeError: this.state.listOfUsers.map is not a function
Uncaught TypeError: this.state.listOfUsers.map is not a function
Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
import React, { Component } from 'react';
import axios from 'axios';
class MeetingItem extends Component {
state = {
meetings: [],
listOfUsers: []
}
componentDidMount() {
//get meeting info
axios.get(`http://localhost:3000/meetings/`+ this.props.match.params.id)
.then(res => {
const meetings = res.data;
this.setState({ meetings });
//console.log(res.data);
});
axios.get(`http://localhost:3000/takePart/`)
.then(res => {
for(var i = 0; i < res.data.length; i++){
//for current meeting
if(res.data[i]['meetingId'] == this.props.match.params.id){
//set listOfUsers
axios.get(`http://localhost:3000/users/`+ res.data[i]['userId'])
.then(res => {
const user = res.data;
this.setState({
listOfUsers : user
});
//in that place data is return
console.log(this.state.listOfUsers);
});
}
}
});
}
takePart = () => {
console.log("take");
const takePart = {
meetingId: this.props.match.params.id,
userId: sessionStorage.getItem('userId'),
};
//x-www-form
let formBody = [];
for (let property in takePart) {
let encodedKey = encodeURIComponent(property);
let encodedValue = encodeURIComponent(takePart[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
axios.post(`http://localhost:8000/takePart`, formBody, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.then(res => {
console.log(res);
console.log(res.data);
//if successfully added a meeting then display alert
if(res.status == "200"){
alert("Thank you. See you later.");
}else{
alert("Sorry we can't handle that. Please repeat for a while.");
}
})
}
render() {
var users = this.state.listOfUsers.map(user => {
return (
<p>{user.firstName}</p>
)
});
return (
<div className="MeetingItem">
<h1>{/*this.props.match.params.id*/}</h1>
<p>Title: {this.state.meetings['title']}</p>
<p>Description: {this.state.meetings['description']}</p>
<p>Author: {this.state.meetings['author']}</p>
<p>lattitude: {this.state.meetings['lattitude']}</p>
<p>longitude: {this.state.meetings['longitude']}</p>
<p>date: {this.state.meetings['date']}</p>
<p>time: {this.state.meetings['time']}</p>
<p>{users}</p>
<div className="btn btn-default" onClick={this.takePart}>Take part</div>
</div>
);
}
}
export default MeetingItem;
Any advice?
Upvotes: 0
Views: 10378
Reputation: 206
Basically, the error says listOfUsers
is not an array (since it doesn't have .map()
method).
It seems, you have an object in your response instead of an array:
axios.get(`http://localhost:3000/users/`+ res.data[i]['userId'])
.then(res => {
const user = res.data;
this.setState({
listOfUsers : user
});
Upvotes: 0
Reputation: 3320
Since it is not an array you can use something like this:
let myState = Object.entries(this.state);
or Object.values();
This will allow you to iterate over each one of those. With Object.entries()
for example you can loop over each key/value pair.
Upvotes: 1
Reputation: 563
Inside your render()
function, change from:
var users = this.state.listOfUsers.map(user => {
return (
<p>{user.firstName}</p>
)
});
To:
var users = [];
if (this.state.listOfUsers) {
user = this.state.listOfUsers.map(user => {
return (
<p>{user.firstName}</p>
)
});
}
Exception thrown is because when render()
is called the first time when the after componentDidMount()
hook, this.state.listOfUsers
is still undefined. You need to set users = []
empty array by default and only call map()
function on the array when it's become an array - after axios promise call resolved. As soon as the axios call is resolved, it well set this.state.listOfUsers
to be an array and render()
is called again to update UI.
Upvotes: 0
Reputation: 156
The API returns list of users should be an array.
To handle this error you can just put a check before map that this.state.listOfUsers
is an array.
i.e.
var users = Array.isArray(this.state.listOfUsers) && this.state.listOfUsers.map(user => {
return (
<p>{user.firstName}</p>
)
});
and also make sure that API axios.get('http://localhost:3000/users/'+ res.data[i]['userId'])
returned the users list is an array for the expected result.
Upvotes: 2