Reputation: 417
Learning react and whilst I understand the life cycle of a component, I don't understand that whilst my JSON call is successful it does not render the list of items I've pulled initially. It does render when I add a new item to the list, but that requires me to click the edit button and add a new element.
var InterBox = React.createClass({
getInitialState: function(){
return {
"content" : [],
"editing" : false,
"pulled" : false
}
},
componentDidMount: function(){
var url = "http://jsonplaceholder.typicode.com/posts";
var tempdata = this.state.content;
$.getJSON(url, function(data){
for (var i = 0; i < data.length; i++) {
var element = data[i];
tempdata.push(element.body);
console.log(tempdata);
}
});
this.setState({"content":tempdata});
this.forceUpdate();
},
addContent: function(e){
var currentContent = this.state.content;
currentContent.push(this.refs.content.value);
this.refs.content.value = "";
this.setState({"content" : currentContent, "editing" : false});
this.render();
},
changeMode: function(e){
this.setState({"editing": true});
this.render();
},
render: function(){
if (this.state.editing)
return(
<div>
<h1>{this.props.title}</h1>
<input type="text" ref="content"/>
<button onClick={this.addContent}>Add</button>
</div>
);
else{
var items = [];
for (var i = 0; i < this.state.content.length; i++) {
var element = this.state.content[i];
items.push(<li>{element}</li>);
}
return(
<div>
<h1>{this.props.title}</h1>
<button onClick={this.changeMode}>Edit</button>
<ul>
{items}
</ul>
</div>
);
}
}
});
ReactDOM.render(
<InterBox title="Hello"></InterBox>,
document.getElementById('main')
);
This is the initial output
This what it should look like
Upvotes: 2
Views: 3213
Reputation: 10421
1.) Since $.getJSON func is async, therefore you should wait response, and after that invoke setState in callback.
let {content} = this.state;
$.getJSON(url,data=>{
let result = data.map(e=>e.body);
this.setState({content:[...content, ...result]});
});
2.) You don't need forceUpdate() and render(), because setState invoke rendering component for you.
3.) You shouldn't mutate your state by push().It will causing problems and bugs. Instead you may use spread operator or concat, etc
//concat returns new array
let {content} = this.state;
this.setState({content:content.concat(result)});
//spread operator
let {content} = this.state;
this.setState({content:[...content, ...result]});
4.) If you don't want to use arrow func in callback, you should use bind(this), otherwise you will have undefined for setState in callback
let {content} = this.state;
$.getJSON(url,function(data){
let result = data.map(e=>e.body);
this.setState({content:content.concat(result)});
}.bind(this));
Upvotes: 5
Reputation: 1655
There is no need for a this.forceUpdate()
or this.render()
call. The screen will be refreshed, i.e. render()
called by React after this.setState()
.
The reason the data isn't being shown is because you're calling this.setState()
immediately after calling $.getJSON()
and not in the success callback of getJSON()
.
This should work:
$.getJSON(url, function(data){
for (var i = 0; i < data.length; i++) {
var element = data[i];
tempdata.push(element.body);
console.log(tempdata);
this.setState({"content":tempdata});
}
});
Upvotes: 0
Reputation: 6803
Dont call render function manually i.e. supposed to call by react. 2.You were setting setState outside your AJAX call response.
var InterBox = React.createClass({
getInitialState: function(){
return {
"content" : [],
"editing" : false,
"pulled" : false
}
},
componentDidMount: function(){
var url = "http://jsonplaceholder.typicode.com/posts";
var tempdata = this.state.content;
$.getJSON(url, function(data){
for (var i = 0; i < data.length; i++) {
var element = data[i];
tempdata.push(element.body);
console.log(tempdata);
}
this.setState({"content":tempdata});
});
},
addContent: function(e){
var currentContent = this.state.content;
currentContent.push(this.refs.content.value);
this.refs.content.value = "";
this.setState({"content" : currentContent, "editing" : false});
},
changeMode: function(e){
this.setState({"editing": true});
},
render: function(){
if (this.state.editing)
return(
<div>
<h1>{this.props.title}</h1>
<input type="text" ref="content"/>
<button onClick={this.addContent}>Add</button>
</div>
);
else{
var items = [];
for (var i = 0; i < this.state.content.length; i++) {
var element = this.state.content[i];
items.push(<li>{element}</li>);
}
return(
<div>
<h1>{this.props.title}</h1>
<button onClick={this.changeMode}>Edit</button>
<ul>
{items}
</ul>
</div>
);
}
}
});
ReactDOM.render(
<InterBox title="Hello"></InterBox>,
document.getElementById('main')
);
Upvotes: 0