Reputation: 1340
I have a array like:
"data": {
"key1": {
"key_val1": "data1",
"key_val2": "data2",
"key_val3": "data3",
"key_val4": "data4",
},
"key2": {
"key_val1": "data1",
"key_val2": "data2",
"key_val3": "data3",
"key_val4": "data4",
},
"key3": {
"key_val1": "data1",
"key_val2": "data2",
"key_val3": "data3",
"key_val4": "data4",
}
}
I want to iterate with this array and populate my table, but I am getting error this.state.data.map() is not a function.
Here is my react component:
import React, { Component } from "react";
import $ from "jquery";
import axios from "axios";
class DataComponent extends Component {
state = {
data: [],
isLoading: true
};
componentDidMount() {
this.getData();
}
getData() {
var curr_date = new Date().toISOString().substring(0, 10);
const params = new FormData();
params.append("date", curr_date);
axios
.post(`http://api.mydomain.in/getdataList/`, params)
.then(res => {
if (res.data.result === 1) {
this.setState({
data: res.data.data,
isLoading: false
});
}
if (!this.state.isLoading) {
this.initTable();
}
})
.catch(err => {
console.log(err);
});
}
initTable() {
$("#my_table").DataTable({
bLengthChange: false,
lengthMenu: [[15, 15, 15, "All"]],
language: {
search: "_INPUT_",
searchPlaceholder: "Search records"
}
});
}
render() {
return (
<div className="tab-pane active" id="mytab">
<div className="inner-content table-responsive">
<table id="my_table" className="display" style={{ width: "100%" }}>
<thead>
<tr className="heading-table">
<th>Col1</th>
<th>col2 </th>
<th>col3 </th>
<th>col4 </th>
<th>col5 </th>
</tr>
</thead>
{this.state.isLoading ? null : (
<tbody>
{this.state.data.map(d => (
<tr>
<td>{d}</td>
<td>{d.key_val1}</td>
<td>{d.key_val2}</td>
<td>{d.key_val3}</td>
<td>{d.key_val4}</td>
</tr>
))}
</tbody>
)}
</table>
</div>
</div>
);
}
}
export default DataComponent;
this.state.data
will be updated with the sample array as shown above.
How can I achieve this?
I have also tried with Object.keys(this.state.data).map()
, but no luck.
Thanks in advance.
Upvotes: 3
Views: 12902
Reputation: 7492
Your data
variable is a JSON object, not an array. To convert it to an array and get both the keys and values, you can use Object.entries
.
This function will return an array containing other arrays with the key as your first value, and the value as the second :
{Object.entries(this.state.data).map(([key, value]) => (
<tr key={key}>
<td>{key}</td>
<td>{value.key_val1}</td>
<td>{value.key_val2}</td>
<td>{value.key_val3}</td>
<td>{value.key_val4}</td>
</tr>
))}
If you do not need the keys of your object, you can use Object.values
.
An alternative using deconstruction :
{Object.entries(this.state.data).map(([key, { key_val1, key_val2, key_val3, key_val4 }]) => (
<tr key={key}>
<td>{key}</td>
<td>{key_val1}</td>
<td>{key_val2}</td>
<td>{key_val3}</td>
<td>{key_val4}</td>
</tr>
))}
Another version using nested mapping, that will work with any kind of objects :
{Object.entries(this.state.data).map(([key, value]) => (
<tr key={key}>
<td>{key}</td>
{Object.entries(value).map(([name, data]) => <td key={name} >{data}</td>)}
</tr>
))}
Upvotes: 7
Reputation: 15688
I believe this is happening because you're trying to pull elements from an array that does not yet have any data through this.state.data.map()
During the initial render, your component state does not have any data in it yet and your getData()
method does not run until AFTER the initial render. You could do a quick initial check to see if your state has data before executing this.state.data.map
like so
{this.state.data ? this.state.data.map(d => (
<tr>
<td>{d}</td>
<td>{d.key_val1}</td>
<td>{d.key_val2}</td>
<td>{d.key_val3}</td>
<td>{d.key_val4}</td>
</tr>
)) : null }
Upvotes: 0