I am facing some difficulties regarding to state in reactjs. As far as I know componentWillMount is a place to load the data with ajax call before the components get rendered. I have a simple simple project which populates stack of panels with a loaded data and show it on board. However the data from ajax call do not get set before rendering of the component and this leads to rendering of the board with an empty array. The follwoing is my complete source:
import React from "react";
export class Panel extends React.Component{
render() {
return (
<div>
<div className="row panel">
<div className="col-sm-12 header">sfsfsf</div>
<div className="col-sm-12 body">fsdfsfs</div>
<div className="col-sm-12 footer">fasfaf</div>
</div>
</div>
);
}
}
and Board class which is a root of the problem is as follows :
import React from "react";
import {Panel} from "./Panel";
export class Board extends React.Component{
constructor(props){
super();
this.state={news: []};
}
componentWillMount(){
this.state={news: []};
$.ajax({
url: "http://localhost:3003/json.txt",
dataType: 'json',
cache: false,
success: function(data) {
var arr=[];
for (var key in data) {
arr.push(data[key]);
console.log(data[key]);
}
this.state={news: arr};
}});
}
render() {
return (
<div>
{
this.state.news.map((item,i)=> <Panel key="i"/>)
}
</div>
);
}
}
Also the last class is index.js:
import React from "react";
import {render} from "react-dom";
import {Board} from "./component/Board";
class App extends React.Component{
render(){
return(
<div>
<Board/>
</div>
);
}
}
render(<App/>, document.getElementById('middle'));
So as you can see in the Board.js class I initialize my array in render function and then I use componentWillMount to fill the news array which I expect it to happen after componentWillMount is finished but in my case the array is empty when rendering happens. Any idea?
*********UPDATE***************
I also tried it with componentDidMount but it did not work and the same problem
componentWillMount() is finishing before render but because ajax is async it will not execute until the request completes.
You should not set state using this.state = .... Instead use:
this.setState({news: arr});
This will set the value and trigger the component and all children to render. Just write your render function to handle null data nicely and you'll have your expected result without blocking JS execution.
As suggested here it is with proper binding:
import React from "react";
import {Panel} from "./Panel";
export class Board extends React.Component{
constructor(props){
super();
}
getInitialState() {
return {news: []};
}
componentWillMount(){
$.ajax({
url: "http://localhost:3003/json.txt",
dataType: 'json',
cache: false,
success: (data) => {
var arr=[];
for (var key in data) {
arr.push(data[key]);
console.log(data[key]);
}
this.setState({news: arr});
}
});
}
render() {
return (
<div>
{
this.state.news.map((item,i)=> <Panel key="i"/>)
}
</div>
);
}
}
The arrow function handles the binding. Simmilar to function(){}.bind(this)
You are doing a ajax call which is async... By definition it will continue to execute the code without waiting for the ajax's response.
you can turn that synchronous by setting async: false on the $.ajax options.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With