-1

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);
Nauman
  • 894
  • 4
  • 14
  • 45
  • This happens because of initial state it's just an empty Array. On `componentDidMount` state property `measurementsData` is empty. Try check state on basics: `if (measurementsData && `statistics ` in measurementsData && ...) {...}`. You initial type of `measurementsData` is doesn't match response data type. In response you get object. – Pavel Petrovich Jun 08 '20 at 09:33

1 Answers1

0

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} />
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • getting the error "TypeError: Cannot read property 'statistics' of undefined" – Nauman Jun 08 '20 at 11:11
  • I have a shared a sample JSON in the description. So, that is how the data will be. – Nauman Jun 08 '20 at 11:14
  • If your data is how you suggest it to be, the updated destructuring code should work for you. Also please follow all the three instructions – Shubham Khatri Jun 08 '20 at 11:21
  • still the same problem. since the `isLoading` is `true`, it is not rendering the rest of the code. When I set `isLoading` to `false`, it renders the rest of the code and I get the same error as before. And yes, I followed all your intructions – Nauman Jun 08 '20 at 11:36
  • in axios success request you haven't set loading to false – Shubham Khatri Jun 08 '20 at 11:45
  • done. still the same issue: "TypeError: Cannot read property 'statistics' of undefined" – Nauman Jun 08 '20 at 11:53
  • What the errors means is that measurements data is undefined which can only happen if axios response.data is undefined – Shubham Khatri Jun 08 '20 at 11:56
  • right. but, I get the response.data in my table and the dropdown and all that is coming from the same Axios request. – Nauman Jun 08 '20 at 11:59
  • Ar3e you sure you used c`const { measurementsData: [{ statistics: {buckets: {values: bucketValues}} }], } = this.state;` to destructure. Take a note of the braces at each level – Shubham Khatri Jun 08 '20 at 12:02
  • checked. all braces are closed. – Nauman Jun 08 '20 at 12:05
  • Its not about closed or not, but about `{}` vs `[]`. Anyways, please try and log each level of output one by one in the code and then try to destructure as a debugging step. I did test the destructuring against the response you gave me and it definitely works – Shubham Khatri Jun 08 '20 at 12:07
  • ok. sure. I literally just copy/paste your code and still got the same error. – Nauman Jun 08 '20 at 12:14
  • I have updated the `destructuring code` in my description. – Nauman Jun 08 '20 at 13:07
  • could you please put your copy of the working code in a codepen or something? thanks. – Nauman Jun 08 '20 at 14:11