我想在 Material UI DataGrid 上显示服务器端分页数据,并使用 swr 获取数据。我一直在研究 DataGrid 中服务器端数据的 MUI 介绍示例,它使用
useEffect
钩子来获取数据,但我已经对其进行了调整 swr
这是我的代码的相关部分
const [paginationModel, setPaginationModel] = useState({
page: 0,
pageSize: 3,
});
const fetcher = (url: RequestInfo) => fetch(url).then((res) => res.json());
const { data, error, isLoading, mutate } = useSWR(
`http://localhost:3002/ingredients/pagination?page=${paginationModel.page}&pageSize=${paginationModel.pageSize}`,
fetcher
);
const rowCountRef = useRef(data?.rowCount || 0);
const rowCount = useMemo(() => {
if (data?.rowCount !== undefined) {
rowCountRef.current = data.rowCount;
}
return rowCountRef.current;
}, [data?.rowCount]);
return (
<Box sx={{ height: 400, width: "100%" }}>
<DataGrid
rows={data?.data ?? []}
rowCount={rowCount}
columns={columns}
loading={loading}
initialState={{
pagination: {
paginationModel: {
pageSize: 5,
},
},
}}
pageSizeOptions={[3, 5, 10, 50]}
disableRowSelectionOnClick
pagination
paginationMode="server"
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
/>
<Button onClick={buttonHandler}>Post</Button>
</Box>
);
我的分页端点返回 json,其中包含一个包含成分元素的
data
字段和一个包含总行数的 rowCount
字段。
我目前所拥有的大部分工作正常,但在某些条件下我看到总行数以及行数据闪烁。
问题场景发生在这些条件下
如果我改用 React 的
useEffect
钩子来进行服务器端分页,这个问题似乎不会发生。分页到新页面时,会显示旧的 rowCount
,直到网络请求返回新的总计数,并且 rowCount
相应更新。之后访问后续页面不会出现使用 swr
时出现的任何闪烁问题
我认为这与缓存问题有关,但我无法理解具体发生了什么。我觉得奇怪的是,对于表中的每个“缓存”页面,
rowCount
属性都持有看似特定于每个页面的缓存值,但 DataGrid
组件本身却有一个单一的 rowCount
属性。我假设第一次重新验证数据时,会计算最新的 rowCount
值,并且后续页面将准确显示,但事实并非如此。
任何人都可以对此提供见解吗?是否有更优雅的方法来处理传入的新数据?在正确的数据流入之前暂时显示缓存的值感觉就像糟糕的用户体验。
链接到代码沙箱
代码沙箱并没有完全实现上面的代码,因为我必须模拟网络请求,但它相当相似。沙箱使用
useEffect
钩子和 swr
实现服务器端分页。要在每种方法之间切换,您需要注释/取消注释 rows
、rowCount
和 loading
的属性(第 97-104 行)
我没有看到任何数据“闪烁”。我所看到的是您向数据添加了一条记录,这增加了行数总数。当您返回上一页时,我看到页面数据被重新验证once,然后总数据行计数更新once以反映当前总计数。
当我切换到您的
useEffect
逻辑时,我在切换页面时看到一个加载指示器。如果这就是您在使用 useSWR
挂钩时想要的全部内容,那么我建议在加载分页数据以及重新验证数据时也使用返回的 isValidating
状态来显示/渲染加载 UI。
const {
data: swrData,
error,
isLoading,
isValidating, // <--
mutate,
} = useSWR(
`pagination?page=${paginationModel.page}&pageSize=${paginationModel.pageSize}`,
fetcher
);
...
<DataGrid
rows={swrData?.data ?? []}
rowCount={rowCount}
loading={isLoading || isValidating} // <-- loading or validating
density="compact"
autoHeight
rowHeight={50}
pagination
paginationMode="server"
pageSizeOptions={[3, 5, 10, 15]}
paginationModel={paginationModel}
columns={[
{ field: "id" },
{ field: "color", headerName: "Color", flex: 1 },
]}
onPaginationModelChange={setPaginationModel}
initialState={{
sorting: {
sortModel: [{ field: "id", sort: "desc" }],
},
}}
/>