Reputation: 2081
What I am trying to do grab json data to render it as an element. Here is what I have, but this.images
continues to come up empty(and undefined/null if I don't set it at the top.
import React, { Component } from 'react';
import axios from 'axios';
export default class Grid extends Component {
constructor(props) {
super(props);
this.images = [];
}
componentWillMount() {
axios.get('grid-config.json')
.then((res) => {
this.setImageArray(res.data);
});
}
setImageArray(imageArray) {
let newArray = [];
for(let i = 0; i < imageArray.length; i++) {
newArray.push(imageArray[i]);
}
this.images = newArray;
}
render() {
const postData = this.props.images;
console.log(this.images);
return (
<div>
hello
</div>
);
}
}
Upvotes: 0
Views: 859
Reputation: 2308
You should use the component's state to hold the image data; when this is updated it will cause the component to render (React will call its render function.)
So, for example, set the component's state something like this:
setImageArray(imageArray) {
let newArray = [];
for(let i = 0; i < imageArray.length; i++) {
newArray.push(imageArray[i]);
}
this.setState({images: newArray });
}
and also initialise this, for example, in the component's constructor:
constructor(props) {
super(props);
this.state = { images: [] };
}
You access the data in the render function as this.state.images.
{See the section entitled A Stateful Component at https://facebook.github.io/react/ }
Upvotes: 3
Reputation: 3540
React components will call render only if the state is changed (except in special cases like initial render or when forceUpdate is called).
Your axios call is async and component is already rendered by the time it executes.
Thus, the render function is called when images is []
, and never called again.
To force a re-render, you have to store the response in state, as pointed in multiple answers or use forceUpdate (not recommended).
EDIT
class Application extends React.Component {
constructor(props) {
super(props)
this.myName = "Sachin"
}
componentDidMount() {
setTimeout(() => {
this.myName = 'Jamie';
// If this is commented out, new value will not reflect in UI.
this.forceUpdate()
})
}
render() {
return (
<div>
<h1>Hello, {this.myName}</h1>
</div>
);
}
}
See this code pen link : https://codepen.io/sach11/pen/ayJaXb
Its very similar to your code, just replaced axios call with a setTimeout.
On line 16, I have a forceUpdate(), which forces a re-render and reflects the new value of this.myName. Otherwise although value is updated, it does not reflect as render is not called again.
Upvotes: 0
Reputation: 2170
in this case you must only manipulate with your state instead of class property. Use setState
method to update your component state. And render images from your updated state.
export default class Grid extends Component {
constructor(props) {
super(props);
this.state = { images: [] };
}
componentWillMount() {
axios.get('grid-config.json')
.then((res) => {
this.setImageArray(res.data);
});
}
setImageArray(imageArray) {
let newArray = [];
for(let i = 0; i < imageArray.length; i++) {
newArray.push(imageArray[i]);
}
this.setState({ images: newArray });
}
render() {
const postData = this.state.images;
console.log(postData);
return (
<div>
hello
</div>
);
}
}
Try this code to render images;
Upvotes: 0