最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React js: this.state.map is not a function - Stack Overflow

programmeradmin2浏览0评论

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. The map is one of Array's methods, so the error occurs. – n8o Commented Jul 15, 2018 at 8:32
Add a ment  | 

4 Answers 4

Reset to default 2

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.

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
            });
发布评论

评论列表(0)

  1. 暂无评论