MUI datagrid -typeError:无法读取未定义的属性(reading' name')

发布于 2025-01-21 17:01:24 字数 2569 浏览 3 评论 0原文

我使用材料UI的dataGrid在表中显示一些数据,我最近切换到REDUX的RTK查询以进行缓存,并摆脱了项目中的全球状态管理,但遇到了标题中提到的问题。

我当前看到的错误是typeError:无法读取未定义的属性(读取'name')

在尝试在嵌套对象中获取数据时会发生这种情况,我正在使用value> valuegetter < /代码>到达嵌套值。下面的const显示了表的列和valuegetter的位置(我删除了此示例的一些列),

const columns = [
    { field: "id", headerName: "ID", width: 70 },
    {
      field: "App",
      headerName: "App",
      width: 110,
      valueGetter: (params) => params.row.app.name, // <---- Recieving error here
      valueFormatter: (params) => capitalise(params.value),
    }
  ];

这就是我的组件的样子(我还删除了一些仅为此示例的代码):

import React, { useEffect, useState } from "react";
import { DataGrid } from "@mui/x-data-grid";
import { IconButton } from "@material-ui/core";
import { CustomLoadingOverlay } from "../gbl/datagrid/DataGridUtils";
import { capitalise } from "../utils/util";
import {
  useGetAppAccountTypesQuery,
  useDeleteAccountTypeMutation,
} from "../../services/reducers/accounttypes";

export default ({ appid }) => {

  const { data, isLoading, isSuccess } = useGetAppAccountTypesQuery(appid);
  const [loading, setLoading] = useState(true);

  console.log(data, isLoading, isSuccess);
  
  // Testing only
  useEffect(() => {
    if (isSuccess) setLoading(false);
  }, [isLoading]);

  const columns = [
    { field: "id", headerName: "ID", width: 70 },
    {
      field: "App",
      headerName: "App",
      width: 110,
      valueGetter: (params) => params.row.app.name,
      valueFormatter: (params) => capitalise(params.value),
    }
  ];
  return (
    <>
      <div
        style={{
          height: 190,
          width: "100%",
          backgroundColor: "white",
          marginTop: 40,
          borderRadius: 4,
        }}
      >
        <DataGrid
          loading={loading}
          rows={data}
          columns={columns}
          components={{
            LoadingOverlay: CustomLoadingOverlay,
          }}
          hideFooter
          density="compact"
          pageSize={6}
          rowsPerPageOptions={[5]}
          checkboxSelection
          disableSelectionOnClick
        ></DataGrid>
      </div>
    </>
  );
};

组件重新呈现几次,每个渲染console.log(数据,isloading,issuccess)看起来

undefined true false <---- this gets logged 3 times
Array(2) false true
Array(2) false true

这个问题似乎是间歇性的,就像它一样有时可以工作,

在切换到RTK查询之前,我使用Axios并使用效果来调用端点,并且从未收到此错误,我在这里做错了吗?

任何帮助将不胜感激。

Im using Material UI's datagrid to show some data in a table, I recently switched over to RTK query from redux for caching and to get rid of the global state management in the project but encountered a problem as mentioned in the title.

The error that I'm currently seeing is TypeError: Cannot read properties of undefined (reading 'name')

This occurs when trying to get data in a nested object, I'm using valueGetter to get to the nested value. The const below shows the columns of the table and where valueGetter is being used (I've removed some of the columns for this example)

const columns = [
    { field: "id", headerName: "ID", width: 70 },
    {
      field: "App",
      headerName: "App",
      width: 110,
      valueGetter: (params) => params.row.app.name, // <---- Recieving error here
      valueFormatter: (params) => capitalise(params.value),
    }
  ];

This is what my component looks like (I've also removed some of the code just for this example):

import React, { useEffect, useState } from "react";
import { DataGrid } from "@mui/x-data-grid";
import { IconButton } from "@material-ui/core";
import { CustomLoadingOverlay } from "../gbl/datagrid/DataGridUtils";
import { capitalise } from "../utils/util";
import {
  useGetAppAccountTypesQuery,
  useDeleteAccountTypeMutation,
} from "../../services/reducers/accounttypes";

export default ({ appid }) => {

  const { data, isLoading, isSuccess } = useGetAppAccountTypesQuery(appid);
  const [loading, setLoading] = useState(true);

  console.log(data, isLoading, isSuccess);
  
  // Testing only
  useEffect(() => {
    if (isSuccess) setLoading(false);
  }, [isLoading]);

  const columns = [
    { field: "id", headerName: "ID", width: 70 },
    {
      field: "App",
      headerName: "App",
      width: 110,
      valueGetter: (params) => params.row.app.name,
      valueFormatter: (params) => capitalise(params.value),
    }
  ];
  return (
    <>
      <div
        style={{
          height: 190,
          width: "100%",
          backgroundColor: "white",
          marginTop: 40,
          borderRadius: 4,
        }}
      >
        <DataGrid
          loading={loading}
          rows={data}
          columns={columns}
          components={{
            LoadingOverlay: CustomLoadingOverlay,
          }}
          hideFooter
          density="compact"
          pageSize={6}
          rowsPerPageOptions={[5]}
          checkboxSelection
          disableSelectionOnClick
        ></DataGrid>
      </div>
    </>
  );
};

The component re-renders a couple of times, from each render the console.log(data, isLoading, isSuccess) looks like

undefined true false <---- this gets logged 3 times
Array(2) false true
Array(2) false true

this issue seems to be intermittent as it does sometimes work,

Before switching to RTK query, I was using Axios and useEffect to call the endpoints and never received this error, am I doing something wrong here?

Any help would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

似最初 2025-01-28 17:01:24

我想说的是,这里与RTK-Q本身无关,这只是一个常见的JS问题\问题,应该缩小到Null-Check。
正常的是,在某些情况下,您可能会产生不确定的结果,应在代码中对其进行处理。可能有几个选项:

  1. 最正确的方法是只返回一个空对象或加载状态(如Spinner \ Skeleton),当数据不确定并且\或data isloading = true = true:

    const {data,isloading,issuccess} = usegetAppApcCountTypesquery(appid);

    如果(!数据|| is Loading)返回&lt;&gt;&gt; skeleton或spinner&lt;/&gt ;;

  2. 通常 - 使用null -SAFE 访问者:

    valuegetter :( params)=&gt; params?row?.app?.name,

  3. 设置data的默认值与某些对象结构相匹配适当的列配置:

    const default_data = {
    排: {
    应用程序: {
    姓名: ””
    }
    }
    }

    const {data = default_data,isloading,issuccess} = usegetAppApcCountTypesquery(appid);

  4. 数据加载期间,当数据不确定时什么都不做:

    const列=数据? [...您的列映射...]:[];

您可以组合使用它们,在加载时间内实现预期的结果。

I would say there is nothing to do with RTK-Q itself here, it's just a common JS problem\question, that should be narrowed to null-check.
It's normal that in some conditions you may have an undefined result, and it should be treated in the code. There may be several options:

  1. The most right way is to just return an empty object or loading state like spinner\skeleton, when data is undefined and\or data isLoading = true :

    const { data, isLoading, isSuccess } = useGetAppAccountTypesQuery(appid);

    if (!data || isLoading) return <>Skeleton or Spinner</>;

  2. In general - use a null-safe ? accessor:

    valueGetter: (params) => params?.row?.app?.name,

  3. Set the default value for data with some object structure that should match your default state for proper column config:

    const DEFAULT_DATA = {
    row: {
    app: {
    name: ""
    }
    }
    }

    const { data = DEFAULT_DATA, isLoading, isSuccess } = useGetAppAccountTypesQuery(appid);

  4. Just do nothing during the data loading, when data is undefined:

    const columns = data ? [...your column mapping...] : [];

You can use them in combination, achieving the expected outcome during the loading time.

请恋爱 2025-01-28 17:01:24

照顾选择模型。即:第一次单击一行或单元格,选择模型是一个带有一个项目的数组:所选行的索引。如果再次单击同一行,则选择模型为空(未选择该行)

  selectionModel={selectionModel}
  onSelectionModelChange={(selection) => {
  const selectionSet = new Set(selectionModel);
  const result = selection.filter((s) => !selectionSet.has(s))
  setSelectionModel(result)
  if(result.length > 0)
    // save de selection model on click on a row
    setRecursoSelected(rows[result[0]])
  else
    // after clicking the same row (unselected) 
    setRecursoSelected({})
  }}

Take care of the selection model. Namely: the first time you click on a row or cell the selection model is an array with one item: the index of the selected row. If you click again on the same row the selection model is empty (the row is unselected)

  selectionModel={selectionModel}
  onSelectionModelChange={(selection) => {
  const selectionSet = new Set(selectionModel);
  const result = selection.filter((s) => !selectionSet.has(s))
  setSelectionModel(result)
  if(result.length > 0)
    // save de selection model on click on a row
    setRecursoSelected(rows[result[0]])
  else
    // after clicking the same row (unselected) 
    setRecursoSelected({})
  }}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文