REACT: destructure a nested array of objects into linear form

801 Views Asked by At

I am fetching data from API using Axios and storing that into a react state variable.

Then, in my render method, I am trying to destructure that fetched data( which is a nested array of objects) into linear form and using it in my react-table.

this is the structure of the fetched data:

[
    { "uuid": "c47dea20",
        "siteName": "dfsf",
        "systemName": "bl",
        "measurementName": ",nk",
        "statistics": {
          "dateStart": "2020-04-20T00:00:00Z",
          "dateStop": "2020-04-21T00:00:00Z",
          "values": [
            "temperature1",
            "temperature2"
          ],
          "min": [1, 2],
          "max": [10, 11],
          "average": [5, 6],
          "last": [7, 8],
          "bucket_size": "4h",
          "buckets": {
            "term": "count",
            "values": [5,4,4,5,6,6]
          }
        }
      }
]

This is how I am trying to destructure:

// gives error: TypeError: Cannot read property 'buckets' of undefined

  const {
    measurementsData: {
      statistics: {
        buckets: [{ values: bucketValues }],
      },
    },
  } = this.state;
  console.log(bucketValues);

Below is the complete code of my component:

class Table extends Component {
    constructor(props) {
      super(props);
      this.state = {
        measurementsData: [],
        isLoading: false,
        dropdownOpen: false,
      };
    }

    signal = axios.CancelToken.source();

    componentDidMount() {
      this.handleGetmeasurementsDataInfo();
      this.addFilterPlaceholder();
    }

    componentWillUnmount() {
      this.signal.cancel("Api is being canceled");
      // fix Warning: Can't perform a React state update on an unmounted component
      this.setState = (state, callback) => {
        return;
      };
    }

    handleGetmeasurementsDataInfo = async () => {
      this.setState({ isLoading: true });
      await axios
        .get("https://run.mocky.io/v3/d2f89c5b-487f-409c-bf2c-705b7d91e12d")
        .then((response) => {
          // handle success
          console.log("measurement data:", response.data);
          this.setState({ measurementsData: response.data });
        })
        .catch((error) => {
          // handle error
          if (axios.isCancel(error)) {
            console.log("Unable to fetch measurementsData", error.message);
          } else {
            this.setState({ isLoading: false });
          }
        });
    };

    addFilterPlaceholder = () => {
      const filters = document.querySelectorAll("div.rt-th > input");
      for (let filter of filters) {
        filter.placeholder = "Search..";
      }
    };

    toggleDropdown = () => {
      this.setState((state) => {
        return {
          dropdownOpen: !state.dropdownOpen,
        };
      });
    };

    render() {
      const { dropdownOpen, measurementsData } = this.state;

      // gives error: TypeError: Cannot read property 'buckets' of undefined
      const {
        measurementsData: {
          statistics: {
            buckets: [{ values: bucketValues }],
          },
        },
      } = this.state;
      console.log(bucketValues);

      return (
        <>
          <div className="content">
            <Row className="mt-5">
              <Col xs={12} md={12}>
                <Card>
                  <CardHeader>
                    <CardTitle tag="h4">heading</CardTitle>
                    <hr />
                    <Dropdown isOpen={dropdownOpen} toggle={this.toggleDropdown}>
                      <DropdownToggle caret>Ships</DropdownToggle>
                      {measurementsData.map((measurementData) => {
                        return (
                          <DropdownMenu key={measurementData.siteName}>
                            <DropdownItem>
                              {measurementData.siteName}
                              <DropdownItem divider />
                            </DropdownItem>
                          </DropdownMenu>
                        );
                      })}
                    </Dropdown>
                  </CardHeader>
                  <CardBody>
                  <p>static data </p>
                    <Line data={chartExample9.data} />
                  <p>dynamic data </p>
                    <Line data={this.bucketValues} />

                    <ReactTable
                      data={[...measurementsData]}
                      pageSize={
                        measurementsData.length > 10
                          ? 10
                          : measurementsData.length
                      }
                      filterable
                      resizable={true}
                      columns={[
                        {
                          Header: "System",
                          accessor: "systemName",
                        },
                        {
                          Header: "Measurement",
                          accessor: "measurementName",
                        },
                        {
                          Header: "Value",
                          accessor: "statistics.values",
                        },
                        {
                          Header: "Min",
                          accessor: "statistics.min",
                        },
                        {
                          Header: "Max",
                          accessor: "statistics.max",
                        },
                        {
                          Header: "Avg",
                          accessor: "statistics.average",
                        },
                        {
                          Header: "Last",
                          accessor: "statistics.last",
                        },
                        {
                          Header: "Bar",
                          <Line  data={this.bucketValues}  />
                        },
                      ]}
                      showPaginationTop
                      showPaginationBottom={false}
                      className="-striped -highlight"
                    />
                  </CardBody>
                </Card>
              </Col>
            </Row>
          </div>
        </>
      );
    }
  }

  export default Table;

UPDATE: updated the destructuring code to below and I now I get "buckets" is undefined

const {
  statistics: {
    buckets: {
      values: [bucketValues],
    },
  },
} = measurementsData;
console.log(bucketValues);
1

There are 1 best solutions below

14
On

You already maintain the loading state, use that to return a loader and access the respective variables only after the data is actually available.

Also note that measurementsData is an array and not an object, so you need to destucture it like one. This is assuming the fact that all bucketValues in each measurementsData object will be same

constructor(props) {
      super(props);
      this.state = {
        measurementsData: [],
        isLoading: true, // set to true initially
        dropdownOpen: false,
      };
    }


...
render() {
      const { dropdownOpen, measurementsData, isLoading } = this.state;

      if(isLoading) {
          return <div>Loading...</div>
      }

      const {
         measurementsData: [{
         statistics: {buckets: {values: bucketValues}}
        }],
      } = this.state;
      console.log(bucketValues);

Also the lineData must use bucketValues and not this.bucketValues since you are not storing this value in class variable

<Line data={bucketValues} />