user8188349
user8188349

Reputation: 237

Material-UI dataGrid with nested data from redux

I am developing a page that fetches data from an API and assembles a table using Material UI and Datagrid. My goal to parse data into the Table. My data looks like this

{
    id: 1,
    device_mrid: "xxx1",
    canaryDeviceId: "xxx",
  },
  {
    id: 2,
    device_mrid: "xxx2",
    canaryDeviceId: "xxx",
  },
  {
    id: 3,
    device_mrid: "xxx3",
    canaryDeviceId: "xxx",
  },

I was able to create a dataGrid table using fake API and the want to get the end result like this https://codesandbox.io/s/bold-leakey-eu3cq?file=/src/App.js

I use the redux state metersList.metersData.data to save meters data.

My code is Looking like this:

import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { readWaterMeter } from "./components/actions/waterActions";
import { FormattedMessage } from "react-intl";
import { DataGrid } from "@material-ui/data-grid";

export default function WaterNew() {
  const dispatch = useDispatch();
  const metersList = useSelector((state) => state.waterReducer);

  useEffect(() => {
    dispatch(readWaterMeter());
  }, [dispatch]);

  let rows = [];
  rows =
   metersList.metersData.data &&
    metersList.metersData.data.length > 0
      ? metersList.metersData.data.map((obj, index) => {
          return (rows = {
            id: index,
            device_mrid: obj.device_mrid,
            canaryDeviceId: obj.canaryDeviceId
          });
        })
      : " ";

  const columns = [
    {
      field: "device_mrid",
      headerName: "device_mrid",
      flex: 1,
      renderCell: ({ value }) => <FormattedMessage id={value} />
    },
    {
      field: "canaryDeviceId",
      headerName: "canaryDeviceId",
      flex: 1,
      renderCell: ({ value }) => <FormattedMessage id={value} />
    }
  ];

  return (
    <div className="App" style={{ height: "100%", width: "100%" }}>
      <DataGrid rows={rows} columns={columns} />
      {console.log("metersList", metersList.metersData.data)}
    </div>
  );
}

I am able to see my meters data in console.log(return) but not able to map.

Initially I got this error:

Uncaught (in promise) TypeError: Cannot read property 'length' of undefined

After that I have added length property then I am getting another error like this

Uncaught (in promise) TypeError: e.forEach is not a function

Now I don't know how to proceed....

And the second issue is I am repeating the renderCell option in Columns, is there any better way to write the renderCell to reduce the lines of code?

I really appreciate the help.

Upvotes: 0

Views: 4416

Answers (2)

user19961075
user19961075

Reputation:

I have similar error "TypeError: Cannot read property 'length' of undefined", but with React Query as data source. Solved it by checking data state, if it "isLoading" - display empty array.

const { isLoading, error, data } = useQuery([apiUrl], () =>
  fetch(apiUrl).then((res) => res.json())
);

<DataGrid
  rows={!isLoading ? data : []}
  columns={columns}
  pageSize={100}
  rowsPerPageOptions={[50]}
  checkboxSelection
  disableSelectionOnClick
  experimentalFeatures={{ newEditingApi: true }}
  components={{ Toolbar: GridToolbar }}
/>;            

Upvotes: 0

user8188349
user8188349

Reputation: 237

After adding an empty array to the useSelector, it worked and also I removed length method and ternary operator from rows.

const metersList = useSelector(
    (state) => state.waterReducer.metersData.data || []
  );


     let rows = [];
  rows = metersList.map((obj, index) => {
    return (rows = {
      id: index,
      device_mrid: obj.device_mrid,
      canaryDeviceId: obj.canaryDeviceId,
    });
  });

Upvotes: 1

Related Questions