我使用Material UI的数据网格在表中显示一些数据,我最近从redux切换到RTK查询进行缓存,并在项目中摆脱全局状态管理,但遇到了标题中提到的问题。
我目前看到的错误是TypeError: Cannot read properties of undefined (reading 'name')
当尝试在嵌套对象中获取数据时,会发生这种情况,我使用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(data, isLoading, isSuccess)
看起来像
undefined true false <---- this gets logged 3 times
Array(2) false true
Array(2) false true
这个问题似乎是间歇性的,因为它有时工作,
在切换到RTK查询之前,我正在使用Axios和useEffect调用端点,从未收到此错误,我在这里做错了吗?
如有任何帮助,不胜感激。
我会说这里与RTK-Q本身无关,它只是一个常见的JS问题,应该缩小到空检查。在某些情况下,您可能会有一个未定义的结果,这是正常的,应该在代码中处理它。可能有几个选项:
-
最正确的方法是返回一个空对象或加载状态,如spinnerskeleton,当数据未定义和或data isLoading = true:
const {data, isLoading, isSuccess} = useGetAppAccountTypesQuery(appid);
如果( !data || isLoading) return <>Skeleton or Spinner;
-
一般-使用null安全的
?
访问器:valueGetter: (params) =>params .row ? .app ? . name,
-
为
const DEFAULT_DATA = {行:{应用:{名称:"}}}data
设置一些对象结构的默认值,这些对象结构应该与您的默认状态相匹配。const {data = DEFAULT_DATA, isLoading, isSuccess} = useGetAppAccountTypesQuery(appid);
-
当数据未定义时,在数据加载期间什么都不做:
const columns = data ?[…你的列映射…[c]: [c];
您可以组合使用它们,在加载期间达到预期的结果。
注意选择模型。即:第一次单击行或单元格时,选择模型是一个包含一个项目的数组:所选行的索引。如果再次单击同一行,则选择模型为空(该行未被选中)
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({})
}}