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 ponentDidMount() 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 ponent. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the ponentWillUnmount method.
import React, { Component } from 'react';
import axios from 'axios';
class MeetingItem extends Component {
state = {
meetings: [],
listOfUsers: []
}
ponentDidMount() {
//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?
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 ponentDidMount() 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 ponent. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the ponentWillUnmount method.
import React, { Component } from 'react';
import axios from 'axios';
class MeetingItem extends Component {
state = {
meetings: [],
listOfUsers: []
}
ponentDidMount() {
//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?
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jul 15, 2018 at 8:02 MarkFroogMarkFroog 211 gold badge2 silver badges3 bronze badges 1-
Check the
res.data
. I am sure that it is not an array. Themap
is one of Array's methods, so the error occurs. – n8o Commented Jul 15, 2018 at 8:32
4 Answers
Reset to default 2The 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.
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.
More info here.
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>
)
});
}
The reason
Exception thrown is because when render()
is called the first time when the after ponentDidMount()
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 bee 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.
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
});