Reputation: 189
I'm learning React and am using the fetch API to send a get request to an HTTP server. I'm able to successfully retrieve the JSON. The code for that is as follows :-
componentDidMount() {
console.log("Send GET request to Go server")
fetch("http://192.168.121.106:8080/site", {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
'Access-Control-Allow-Origin': '*',
}
}).then(response => {
if(response.status === 200) {
response.text().then(data => {
this.setState({
siteData : data
});
});
}
})
}
I want to render this JSON in the form of a table. siteData is an object. This is what I have in my render function :-
render() {
const siteVar = JSON.stringify(this.state.siteData);
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th >S. NO.</th>
<th >NAME</th>
<th >AGE</th>
</tr>
</thead>
<tbody>
{ (this.state.siteData).map(site =>
<tr>
<td> {site.name} </td>
<td> {site.age} </td>
</tr>
)}
</tbody>
</table>
</React.Fragment>
)
}
}
With this code, I'm getting an error that:
this.state.siteData.map is not a function
What am I doing wrong here?
This is a sample of what the JSON will look like :-
{
"1": {
"name": "Alice",
"age": "23",
},
"2": {
"name": "Bob",
"age": "25",
}
}
Upvotes: 0
Views: 176
Reputation: 4425
The reason why you're getting an error is because you're trying to use the map
method on an object
. You need to turn your object
into an array
to be able to use map
and store that in your state
instead.
const response = {
"1": {
"name": "Alice",
"age": "23",
},
"2": {
"name": "Bob",
"age": "25",
}
}
const responseAsArray = Object.keys(response)
.map(key => {
return {
siteNum: key,
...response[key]
}
})
console.log(responseAsArray)
Going back to your code, it'd look like the following:
componentDidMount() {
fetch(...)
.then(response => {
// Note the use of `.json()` here
// if your API returns some JSON as a response
// use this instead of `text()` since it will
// parse a JSON response into native JavaScript objects
if (response.status === 200) {
return response.json()
}
// TODO: handle errors appropriately
})
.then(json => {
const siteData = Object.keys(json).map(key => {
return { siteNum: key, ...json[key] }
})
this.setState({ siteData })
})
.catch(/* TODO: handle errors appropriately */)
}
Here's a working example:
class App extends React.Component {
state = { siteData: [] };
componentDidMount() {
fakeFetch()
.then(response => {
if (response.status === 200) {
return response.json();
}
})
.then(data => {
const siteData = Object.keys(data).map(key => {
return { siteNum: key, ...data[key] };
});
this.setState({ siteData });
})
.catch(console.error);
}
render() {
const { siteData } = this.state;
if (siteData.length === 0) {
return "Loading";
}
return (
<table>
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>AGE</th>
</tr>
</thead>
<tbody>
{siteData.map(({ siteNum, name, age }) => (
<tr key={siteNum}>
<td>{siteNum}</td>
<td>{name}</td>
<td>{age}</td>
</tr>
))}
</tbody>
</table>
);
}
}
// NOTE:
// This assumes your API returns a JSON response
// that looks like like this:
// {"1":{"name":"Alice","age":"23"},"2":{"name":"Bob","age":"25"}}
function fakeFetch() {
return Promise.resolve({
status: 200,
json: () => {
return {
"1": {
name: "Alice",
age: "23"
},
"2": {
name: "Bob",
age: "25"
}
};
}
});
}
ReactDOM.render(
<App />,
document.getElementById("app")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Upvotes: 2