Search code examples
reactjsdestructuringreact-table

React: React-table not rendering data multiple different state variables


I am using this react-table component library. I have a data state variable with three state variables in it and I am making three API calls to fetch data for all three of them. Then, in JSX I am destructuring that response.data and passing it inside data of react-table component. But, it's not working.

Code for my react-table component:

import React, { Component } from "react";
// react component for creating dynamic tables
import ReactTable from "react-table";

import axios from "axios";
import {
  Card,
  CardBody,
  CardHeader,
  CardTitle,
  Row,
  Col,
  Dropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
} from "reactstrap";

class DataViewTable extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: {
        system: [],
        measurements: [],
        measurementData: [],
      },
      isLoading: false,
      dropdownOpen: false,
    };
  }

  signal = axios.CancelToken.source();

  componentDidMount() {
    this.handleGetSystemInfo();
    this.handleGetMeasurementsInfo();
    this.handleGetMeasurementDataInfo();
    this.addFilterPlaceholder();
  }

  componentUnMount() {
    this.signal.cancel("Api is being canceled");
  }
  handleGetSystemInfo = async () => {
    this.setState({ isLoading: true });
    await axios
      .get("http://www.mocky.io/v2/5ed488f83300005f00f7a20e")
      .then((response) => {
        // handle success
        console.log("system:", response.data);
        this.setState({ system: response.data });
      })
      .catch((error) => {
        // handle error
        if (axios.isCancel(error)) {
          console.log("Unable to fetch system data", error.message);
        } else {
          this.setState({ isLoading: false });
        }
      });
  };
  handleGetMeasurementsInfo = async () => {
    this.setState({ isLoading: true });
    await axios
      .get("http://www.mocky.io/v2/5ed4899d3300003f00f7a212")
      .then((response) => {
        // handle success
        console.log("measurements:", response.data);
        this.setState({ measurements: response.data });
      })
      .catch((error) => {
        // handle error
        if (axios.isCancel(error)) {
          console.log("Unable to fetch measurements info", error.message);
        } else {
          this.setState({ isLoading: false });
        }
      });
  };
  handleGetMeasurementDataInfo = async () => {
    this.setState({ isLoading: true });
    await axios
      .get("http://www.mocky.io/v2/5ed48a113300007900f7a213")
      .then((response) => {
        // handle success
        console.log("measurement data:", response.data);
        this.setState({ measurementData: response.data });
      })
      .catch((error) => {
        // handle error
        if (axios.isCancel(error)) {
          console.log("Unable to fetch measurementData", 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 } = this.state;
    const { system, measurementData, measurements } = this.state.data;
    return (
      <>
        <div className="content">
          <Row className="mt-5">
            <Col xs={12} md={12}>
              <Card>
                <CardHeader>
                  <CardTitle tag="h4">Table of data</CardTitle>
                  <hr />
                  <Dropdown
                    isOpen={dropdownOpen}
                    toggle={this.toggleDropdown}
                    className="shipsDropdown"
                  >
                    <DropdownToggle caret>Ships</DropdownToggle>
                    <DropdownMenu>
                      <DropdownItem>Foo Action</DropdownItem>
                      <DropdownItem divider />
                      <DropdownItem>Bar Action</DropdownItem>
                      <DropdownItem divider />
                      <DropdownItem>Quo Action</DropdownItem>
                    </DropdownMenu>
                  </Dropdown>
                </CardHeader>
                <CardBody>
                  <ReactTable
                    data={(system, measurements, measurementData)}
                    filterable
                    resizable={false}
                    columns={[
                      {
                        Header: "System",
                        accessor: "name",
                      },
                      {
                        Header: "Measurement",
                        accessor: "name",
                      },
                      {
                        Header: "Value",
                        accessor: "values.temp1, values.temp2",
                      },
                      {
                        Header: "Min",
                        accessor: "",
                      },
                      {
                        Header: "Max",
                        accessor: "",
                      },
                      {
                        Header: "Avg",
                        accessor: "",
                      },
                      {
                        Header: "Last",
                        accessor: "",
                      },
                      {
                        Header: "Bar",
                        accessor: "",
                      },
                    ]}
                    showPaginationTop
                    showPaginationBottom={false}
                    className="-striped -highlight"
                  />
                </CardBody>
              </Card>
            </Col>
          </Row>
        </div>
      </>
    );
  }
}

export default DataViewTable;

Adding CodeSandbox link


Solution

  • There are multiple things that need to be handled correctly here

    • You have set state as measurementData, measurements and system directly and not under data in the axios request so you must use them directly
     constructor(props) {
        super(props);
        this.state = {
            system: [],
            measurements: [],
            measurementData: [],
          ...
        };
      }
    
    • You are not passing the cancelToken to the axios request. Also a separate cancelToken must be used individual calls
    this.signalToken = axios.CancelToken.source();
    await axios
          .get("http://www.mocky.io/v2/5ed48a113300007900f7a213", {
             cancelToken: this.signalToken.token
          })
    
    

    and so on for the other requests and cancel the request like

    this.signalToken.cancel();
    this.measurementsToken.cancel()
    this.measurementsDataToken.cancel()
    
    
    • The data to ReactTable should be an array of merged resource if they have the same format. However they have different format, you should consider rendering multiple ReactTables
    <ReactTable
        data={[...system, ...measurements, ...measurementData]}
        filterable
        resizable={false}