3

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.

2 Answers 2

7

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>
))}
Sign up to request clarification or add additional context in comments.

Comments

0

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 }

1 Comment

Yes, because of this I have used this.state.isLoading. Initially the value is true, and the this.state.data.map would not be executed. I am making it false when the this.state.data has been populated with the api call.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.