React JS - Uncaught TypeError: this.props.data.map bukan sebuah fungsi


110

Saya bekerja dengan reactjs dan sepertinya tidak dapat mencegah kesalahan ini ketika mencoba menampilkan data JSON (baik dari file atau server):

Uncaught TypeError: this.props.data.map is not a function

Saya telah melihat:

React code melempar "TypeError: this.props.data.map bukanlah sebuah fungsi"

React.js this.props.data.map () bukanlah sebuah fungsi

Tidak satu pun dari ini yang membantu saya memperbaiki masalah. Setelah halaman saya dimuat, saya dapat memverifikasi bahwa this.data.props tidak tidak terdefinisi (dan memang memiliki nilai yang setara dengan objek JSON - dapat memanggil dengan window.foo), jadi sepertinya tidak memuat tepat waktu ketika dipanggil oleh ConversationList. Bagaimana cara memastikan bahwa mapmetode ini berfungsi pada data JSON dan bukan undefinedvariabel?

var converter = new Showdown.converter();

var Conversation = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (
      <div className="conversation panel panel-default">
        <div className="panel-heading">
          <h3 className="panel-title">
            {this.props.id}
            {this.props.last_message_snippet}
            {this.props.other_user_id}
          </h3>
        </div>
        <div className="panel-body">
          <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
        </div>
      </div>
    );
  }
});

var ConversationList = React.createClass({
  render: function() {

    window.foo            = this.props.data;
    var conversationNodes = this.props.data.map(function(conversation, index) {

      return (
        <Conversation id={conversation.id} key={index}>
          last_message_snippet={conversation.last_message_snippet}
          other_user_id={conversation.other_user_id}
        </Conversation>
      );
    });

    return (
      <div className="conversationList">
        {conversationNodes}
      </div>
    );
  }
});

var ConversationBox = React.createClass({
  loadConversationsFromServer: function() {
    return $.ajax({
      url: this.props.url,
      dataType: 'json',
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadConversationsFromServer();
    setInterval(this.loadConversationsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (
      <div className="conversationBox">
        <h1>Conversations</h1>
        <ConversationList data={this.state.data} />
      </div>
    );
  }
});

$(document).on("page:change", function() {
  var $content = $("#content");
  if ($content.length > 0) {
    React.render(
      <ConversationBox url="/conversations.json" pollInterval={20000} />,
      document.getElementById('content')
    );
  }
})

EDIT: menambahkan contoh percakapan.json

Catatan - memanggil this.props.data.conversationsjuga mengembalikan kesalahan:

var conversationNodes = this.props.data.conversations.map...

mengembalikan kesalahan berikut:

TypeError Tidak Tertangkap: Tidak dapat membaca 'peta' properti dari yang tidak ditentukan

Berikut ini Conversations.json:

{"user_has_unread_messages":false,"unread_messages_count":0,"conversations":[{"id":18768,"last_message_snippet":"Lorem ipsum","other_user_id":10193}]}

Saya telah memperbarui jawabannya. Selain itu, beberapa rekomendasi: tambahkan propTypes: {data: React.PropTypes.array} ke ConversationList untuk memverifikasi tipe data, dan tambahkan componentWillUnmount: fn () yang "clearInterval" interval di ConversationBox.
pengguna120242

Jawaban:


134

The .mapFungsi ini hanya tersedia pada array.
Sepertinya datatidak dalam format yang Anda harapkan (memang {} tetapi Anda mengharapkan []).

this.setState({data: data});

seharusnya

this.setState({data: data.conversations});

Periksa jenis "data" yang disetel, dan pastikan itu adalah larik.

Kode yang dimodifikasi dengan beberapa rekomendasi (validasi propType dan clearInterval):

var converter = new Showdown.converter();

var Conversation = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (
      <div className="conversation panel panel-default">
        <div className="panel-heading">
          <h3 className="panel-title">
            {this.props.id}
            {this.props.last_message_snippet}
            {this.props.other_user_id}
          </h3>
        </div>
        <div className="panel-body">
          <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
        </div>
      </div>
    );
  }
});

var ConversationList = React.createClass({
 // Make sure this.props.data is an array
  propTypes: {
    data: React.PropTypes.array.isRequired
  },
  render: function() {

    window.foo            = this.props.data;
    var conversationNodes = this.props.data.map(function(conversation, index) {

      return (
        <Conversation id={conversation.id} key={index}>
          last_message_snippet={conversation.last_message_snippet}
          other_user_id={conversation.other_user_id}
        </Conversation>
      );
    });

    return (
      <div className="conversationList">
        {conversationNodes}
      </div>
    );
  }
});

var ConversationBox = React.createClass({
  loadConversationsFromServer: function() {
    return $.ajax({
      url: this.props.url,
      dataType: 'json',
      success: function(data) {
        this.setState({data: data.conversations});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  getInitialState: function() {
    return {data: []};
  },

 /* Taken from 
    https://facebook.github.io/react/docs/reusable-components.html#mixins
    clears all intervals after component is unmounted
  */
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.map(clearInterval);
  },

  componentDidMount: function() {
    this.loadConversationsFromServer();
    this.setInterval(this.loadConversationsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (
      <div className="conversationBox">
        <h1>Conversations</h1>
        <ConversationList data={this.state.data} />
      </div>
    );
  }
});

$(document).on("page:change", function() {
  var $content = $("#content");
  if ($content.length > 0) {
    React.render(
      <ConversationBox url="/conversations.json" pollInterval={20000} />,
      document.getElementById('content')
    );
  }
})

32

apa yang berhasil untuk saya adalah mengubah props.data menjadi sebuah array menggunakan data = Array.from(props.data); maka saya dapat menggunakan data.map()fungsinya


1
Tipe saya adalah array yang sudah misalnya typeOf menunjukkan hal yang benar juga panjangnya benar tetapi tetap saja, kesalahannya muncul. Ini memperbaikinya untuk saya. Terima kasih!
pengguna1829319

10

Secara lebih umum, Anda juga dapat mengonversi data baru menjadi array dan menggunakan sesuatu seperti concat:

var newData = this.state.data.concat([data]);  
this.setState({data: newData})

Pola ini sebenarnya digunakan di aplikasi demo ToDo Facebook (lihat bagian "Aplikasi") di https://facebook.github.io/react/ .


1
Ini adalah tip / trik yang rapi, tetapi saya ingin mencatat bahwa ini akan menutupi masalah sebenarnya dan tidak akan menyelesaikan OP. Dalam kasus OP, ini tidak akan membantu, karena datanya masih dalam format yang salah (bukan yang dimaksudkan). Percakapan kemungkinan besar akan berakhir kosong karena semua properti akan menjadi nol. Saya akan merekomendasikan untuk tidak menggunakan tip ini, kecuali Anda yakin data Anda dalam format yang Anda inginkan, jadi Anda tidak berakhir dengan perilaku yang tidak terduga ketika data yang dikembalikan tidak sesuai dengan yang Anda pikirkan.
pengguna120242

1

Anda tidak memerlukan array untuk melakukannya.

var ItemNode = this.state.data.map(function(itemData) {
return (
   <ComponentName title={itemData.title} key={itemData.id} number={itemData.id}/>
 );
});

Apa bedanya bro?
Amar Pathak

1

Ini terjadi karena komponen dirender sebelum data asinkron tiba, Anda harus mengontrol sebelum merender.

Saya menyelesaikannya dengan cara ini:

render() {
    let partners = this.props && this.props.partners.length > 0 ?
        this.props.partners.map(p=>
            <li className = "partners" key={p.id}>
                <img src={p.img} alt={p.name}/> {p.name} </li>
        ) : <span></span>;

    return (
        <div>
            <ul>{partners}</ul>
        </div>
    );
}
  • Peta tidak dapat menyelesaikan saat properti null / undefined, jadi saya melakukan kontrol terlebih dahulu

this.props && this.props.partners.length > 0 ?


0

Anda perlu mengubah objek menjadi array untuk menggunakan mapfungsi:

const mad = Object.values(this.props.location.state);

di mana this.props.location.stateobjek yang diteruskan ke komponen lain.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.