FNGR FNGR - 5 months ago 229
Javascript Question

React Tutorial and Sinatra API: Uncaught TypeError: this.props.data.map is not a function

I know, there are hundreds of questions with the same title, but nothing helped my get a solution for my problem. so I worked through the official react js tutorial and build a small API with sinatra to test things.

so everything works really good. except of one error I see in the console when submitting a new "Joke" (called them jokes instead of comments ;)) via AJAX.

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


This happens when I click on submit. I logged the state when submitting the form and everything seems to be okay (array with the temporary objects).

so the new Joke is being added and written to the database. It works but i don't know why I'm getting the Uncaught TypeError in the console.

thanks in advance!

var JokeBox = React.createClass({
loadJokesFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
handleJokeSubmit: function(joke) {
var jokes = this.state.data;
var tmpJoke = jQuery.extend({}, joke)
tmpJoke.id = new Date();
tmpJoke.likes = 0;
jokes.unshift(tmpJoke);
this.setState({data: jokes}, function(){
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: joke,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
this.setState({data: jokes});
console.error(this.props.url, status, err.toString());
}.bind(this)
});
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadJokesFromServer();
setInterval(this.loadJokesFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="jokes">
<h1>Jokes</h1>
<JokeForm onJokeSubmit={this.handleJokeSubmit} />
<JokeList data={this.state.data} />
</div>
);
}
});

var JokeList = React.createClass({
render: function() {
var jokeNodes = this.props.data.map(function(joke) {
return (
<Joke content={joke.content} key={joke.id} likes={joke.likes} />
);
});
return (
<div className="jokeList">
{jokeNodes}
</div>
);
}
});

var JokeForm = React.createClass({
getInitialState: function() {
return {content: ''};
},
handleContentChange: function(e) {
this.setState({content: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var content = this.state.content.trim();
if (!content) {
return;
}
this.props.onJokeSubmit({content: content});
this.setState({content: ''});
},
render: function() {
return (
<form className="jokesForm" onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Your Joke!"
value={this.state.content}
onChange={this.handleContentChange}
/>
<input type="submit" value="Send joke" />
</form>
);
}
});

var Joke = React.createClass({
render: function() {
return (
<div className="joke">
<p className="jokeContent">{this.props.content}</p>
<p className="jokeLikes">{this.props.likes}</p>
</div>
);
}
});

ReactDOM.render(
<JokeBox url="/api/jokes" pollInterval={2000} />,
document.getElementById('app')
);


// EDIT

So I played around with the sample tutorial repo from the tutorial. I log the data in the handleSubmit in the success function right before the state is set. And I figured out: my data is ja object of the actual new Joke, in the sample tutorial it is an array of all comments. How could this be? I can't find my mistake...

Answer

try

handleJokeSubmit: function(joke) {

    let {data}= this.state;

    $.post(this.props.url, joke, res=>{
       this.setState({data:[res,...data]});
    })
   .fail( err=>alert('Error: ' + err.responseText));
}

///EDIT es5

handleJokeSubmit: function(joke) {

    var data = this.state.data;

    $.post(this.props.url, joke, function(res){
       this.setState({data:[res].concat(data)});
    }.bind(this))
   .fail( function(err){alert('Error: ' + err.responseText)});
}