Reputation: 327
I am trying to loop through json_obj after it loads using async XMLHttpRequest()
but as json_obj is null at the start map() crashes.
Here is my code:
import React, { Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
class ImageViewer extends React.Component {
constructor() {
super();
this.state = {
loading: true,
json_obj : null,
link: "https://api.github.com/users/github/repos"
}
}
componentDidMount() {
var xhr = new XMLHttpRequest();
xhr.open("GET", this.state.link, true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
this.setState({ json_obj :JSON.parse(xhr.responseText).sort(function(a, b){var keyA = new Date(a.updated_at),keyB = new Date(b.updated_at);if(keyA > keyB) return -1;if(keyA < keyB) return 1;return 0;})});
} else {
console.error(xhr.statusText);
}
}
}.bind(this);
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.send(null);
}
render() {
return (
<div>
{this.state.json_obj.map((obj, index) => {
return (
<div >
<h1>{obj.name}</h1>
<h1>{obj.updated_at}</h1>
</div>
)
})}
</div>
)
}}
ReactDOM.render(
<ImageViewer />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
: <div id="root"></div>
I tried to use conditional rendering but it throws errors as well:
import React, { Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
class ImageViewer extends React.Component {
constructor() {
super();
this.state = {
loading: true,
json_obj : null,
link: "https://api.github.com/users/github/repos",
stuff : {name:"loading", updated_at:"loading"}
}
}
componentDidMount() {
var xhr = new XMLHttpRequest();
xhr.open("GET", this.state.link, true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
this.setState({ json_obj :JSON.parse(xhr.responseText).sort(function(a, b){var keyA = new Date(a.updated_at),keyB = new Date(b.updated_at);if(keyA > keyB) return -1;if(keyA < keyB) return 1;return 0;})});
} else {
console.error(xhr.statusText);
}
}
}.bind(this);
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.send(null);
}
render() {
return (
<div>
{(this.state.json_obj ? this.state.json_obj : this.state.stuff).map((obj, index) => {
return (
<div >
<h1>{obj.name}</h1>
<h1>{obj.updated_at}</h1>
</div>
)
})}
</div>
)
}}
ReactDOM.render(
<ImageViewer />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Upvotes: 0
Views: 3053
Reputation: 7207
The first code you provided throws an error because json_obj
is null
as you mentioned. But the second one throws an error because you are trying to map
over the object this.state.stuff
which you can not do. So there are actually a couple of things you can do:
wrap stuff
inside an array:
return (
<div>
{(this.state.json_obj ? this.state.json_obj : [this.state.stuff]).map((obj, index) => {
return (
<div >
<h1>{obj.name}</h1>
<h1>{obj.updated_at}</h1>
</div>
)
})}
</div>
or you can wrap it when defining it:
constructor() {
super();
this.state = {
loading: true,
json_obj : null,
link: "https://api.github.com/users/github/repos",
stuff : [{name:"loading", updated_at:"loading"}]
}
}
or you can simply check if json_obj
is available and rendering something else (or nothing) instead.
renders nothing if json_obj
is not available
return (
<div>
{this.state.json_obj && this.state.json_obj.map((obj, index) => {
return (
<div >
<h1>{obj.name}</h1>
<h1>{obj.updated_at}</h1>
</div>
)
})}
</div>
)
renders a loading message when json_obj is not available
return (
<div>
{
this.state.json_obj ?
this.state.json_obj.map((obj, index) => {
return (
<div >
<h1>{obj.name}</h1>
<h1>{obj.updated_at}</h1>
</div>
)
}) : <div>Loading...</div>
}
</div>
)
Upvotes: 1
Reputation: 66355
So check if it's null and return something else:
if (!this.state.json_obj) {
return <div>Loading...</div>;
}
return (
<div>
{this.state.json_obj.map((obj, index) => (
<div key={obj.name}>
<h1>{obj.name}</h1>
<h1>{obj.updated_at}</h1>
</div>
))}
</div>
)
Your code was throwing because this.state.stuff
is an object and you can't iterate over an object with .map
. If this.state.json_obj
is also an object and not an array you would need to do Object.keys(this.state.json_obj).map(...
.
Upvotes: 3