web-dev-qa-db-de.com

React JS - Nicht gefundener TypeError: this.props.data.map ist keine Funktion

Ich arbeite mit reactjs und kann diesen Fehler beim Anzeigen von Json-Daten (entweder von einer Datei oder einem Server) nicht verhindern:

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

Ich habe angeschaut:

Reagieren Sie den Code, der "TypeError: this.props.data.map ist keine Funktion" ausgibt.

React.js this.props.data.map () ist keine Funktion

Keines davon hat mir geholfen, das Problem zu lösen. Nachdem meine Seite geladen wurde, kann ich überprüfen, ob this.data.props nicht undefiniert ist (und einen Wert hat, der dem json-Objekt entspricht - kann mit window.foo aufgerufen werden). Es scheint also, als würde es nicht rechtzeitig geladen, wenn es aufgerufen wird von ConversationList. Wie stelle ich sicher, dass die map-Methode an den Json-Daten und nicht an einer undefined-Variablen arbeitet?

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

BEARBEITEN: Hinzufügen des Beispiels conversations.json

Hinweis - Der Aufruf von this.props.data.conversations gibt auch einen Fehler zurück:

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

kehrt zurück 

Uncaught TypeError: Cannot read property 'map' of undefined

Hier ist conversations.json:

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

61
keypulsations

Die .map-Funktion ist nur für ein Array verfügbar.
Es sieht so aus, als wäre data nicht in dem Format, in dem Sie es erwarten (es ist {}, aber Sie erwarten []).

this.setState({data: data});

sollte sein

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

Prüfen Sie, auf welchen Typ "Daten" eingestellt ist, und stellen Sie sicher, dass es sich um ein Array handelt.

Modifizierter Code mit einigen Empfehlungen (PropType-Validierung und 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')
    );
  }
})
82
user120242

was für mich funktioniert hat, ist die Konvertierung der props.data in ein Array mit data = Array.from(props.data); Dann könnte ich die Funktion data.map() verwenden 

10

Im Allgemeinen können Sie die neuen Daten auch in ein Array konvertieren und so etwas wie concat verwenden: 

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

Dieses Muster wird in der ToDo-Demo-App von Facebook (siehe Abschnitt "Eine Anwendung") unter https://facebook.github.io/react/ verwendet. 

8
bresson

Dies geschieht, weil die Komponente vor dem Eintreffen der asynchronen Daten gerendert wird. Sie sollten dies vor dem Rendern steuern.

Ich habe es so gelöst: 

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>
    );
}
  • Die Karte kann nicht aufgelöst werden, wenn die Eigenschaft null/undefined ist. Daher habe ich zuerst eine Kontrolle ausgeführt 

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

1
J C

Sie brauchen dafür kein Array. 

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

versuchen Sie componentDidMount() Lebenszyklus, wenn Sie Daten abrufen

0
Arif Ramadhani