React JS - Yakalanmamış TypeError: this.props.data.map bir işlev değil


112

Reactjs ile çalışıyorum ve JSON verilerini görüntülemeye çalışırken bu hatayı önleyemiyorum (dosya veya sunucudan):

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

Baktım:

React kodu atarak "TypeError: this.props.data.map bir işlev değildir"

React.js this.props.data.map () bir işlev değildir

Bunların hiçbiri sorunu çözmeme yardımcı olmadı. Sayfam yüklendikten sonra this.data.props'un tanımsız olmadığını (ve JSON nesnesine eşdeğer bir değere sahip olduğunu - çağırabilir window.foo), bu nedenle tarafından çağrıldığında zamanında yüklenmiyor gibi görünüyor. Konuşma Listesi. mapYöntemin bir undefineddeğişken değil, JSON verileri üzerinde çalıştığından nasıl emin olabilirim ?

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')
    );
  }
})

DÜZENLEME: örnek konuşmalar.json ekleme

Not - çağrı yapmak this.props.data.conversationsda bir hata döndürür:

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

aşağıdaki hatayı döndürür:

Yakalanmamış TypeError: Tanımsız 'eşleme' özelliği okunamıyor

İşte chatations.json:

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

Cevabı güncelledim. Ayrıca, bazı öneriler: verilerin türünü doğrulamak için ConversationList'e propTypes: {data: React.PropTypes.array} ekleyin ve ConversationBox'taki aralığı "clearInterval" olan bir componentWillUnmount: fn () ekleyin.
user120242

Yanıtlar:


136

.mapİşlev dizisinde kullanılabilir.
Görünüşe datagöre olmasını beklediğiniz biçimde değil ({} ama [] bekliyorsunuz).

this.setState({data: data});

olmalı

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

Hangi tür "veri" olarak ayarlandığını kontrol edin ve bunun bir dizi olduğundan emin olun.

Birkaç öneriyle değiştirilmiş kod (propType doğrulaması ve 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')
    );
  }
})

33

benim için işe yarayan şey, props.data'yı kullanarak bir diziye dönüştürmek, data = Array.from(props.data); o zaman data.map()işlevi kullanabilirim


1
Benim tipim zaten bir diziydi, örneğin typeOf doğru şeyi gösteriyordu, uzunluk da doğruydu ama yine de hata görünüyordu. Bu benim için düzeltti. Teşekkürler!
user1829319

10

Daha genel olarak, yeni verileri bir diziye dönüştürebilir ve concat gibi bir şey kullanabilirsiniz:

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

Bu kalıp aslında Facebook'un ToDo demo uygulamasında ("Uygulama" bölümüne bakın) https://facebook.github.io/react/ adresinde kullanılmaktadır .


1
Bu güzel bir ipucu / numara, ancak bunun gerçek sorunu maskeleyeceğini ve OP'yi çözmeyeceğini belirtmek isterim. OP durumunda, veriler yine de yanlış biçimlendirilmiş olacağından (amaçlanan değil) bu yardımcı olmaz. Tüm sahne öğeleri boş olacağından konuşma büyük olasılıkla boş kalacaktır. Verilerinizin istediğiniz formatta olduğundan emin değilseniz, bu ipucunu kullanmamanızı tavsiye ederim, böylece döndürülen veriler olması gerektiğini düşündüğünüz gibi olmadığında beklenmedik davranışlarla karşılaşmazsınız.
user120242

1

Bunu yapmak için bir diziye ihtiyacınız yok.

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

Nasıl farklıdır kardeşim?
Amar Pathak

1

Bu, bileşen eşzamansız veriler gelmeden önce işlendiği için olur, işlemeden önce kontrol etmeniz gerekir.

Bunu şu şekilde çözdüm:

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>
    );
}
  • Özellik null / undefined olduğunda harita çözülemiyor, bu yüzden önce bir kontrol yaptım

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


0

mapİşlevi kullanmak için nesneyi bir diziye dönüştürmeniz gerekir :

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

this.props.location.stateiletilen nesne başka bir bileşene nerede .


-2

componentDidMount()veri alırken yaşam döngüsünü deneyin


5
Ayrıca, biraz açıklama sağlayın, bu neden ve nasıl çalışıyor?
Mittal Patel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.