0

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.

3
  • I think that the error is from dispatch(readWaterMeter()) because it says that the error was in promise. If you remove everything from the component except that useEffect and just return null, do you still see the error? If so, please post the code of your readWaterMeter function. Commented Mar 26, 2021 at 21:28
  • You want const data = useSelector((state) => state.waterReducer.metersData.data || []); because a selector should select the minimum amount of data that you need. I don't know why you would use the index as an id when it seems like they already have an id property but that would be const rows = data.map((obj, i) => ({ ...obj, id: i })); Commented Mar 26, 2021 at 21:39
  • Hello @LindaPaiste.. Thank you so much for the response... There is no problem with my dispatch method... The problem is with useSelector method, after adding an empty array ( || [] ) to my selector it worked... I am able to see the data... You saved my day... Thank you so much Commented Mar 26, 2021 at 23:16

2 Answers 2

1

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,
    });
  });

Sign up to request clarification or add additional context in comments.

1 Comment

This does the same thing as your rows section: const rows = metersList.map((obj, i) => ({ ...obj, id: i })). That's really all you need :)
0

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 }}
/>;            

Comments

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.