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}]}
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')
);
}
})
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
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.
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>
);
}
this.props && this.props.partners.length > 0 ?
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}/>
);
});
versuchen Sie componentDidMount()
Lebenszyklus, wenn Sie Daten abrufen