如何获取MUI Data Grid当前页数据及实现通知标记已读求助
解决方案:MUI Data Grid 标记当前页未读通知为已读
问题根源
你之前在renderCell中直接调用父组件的setUnread,属于在组件渲染阶段更新状态,违反了React的渲染规则(渲染过程中不能触发状态更新),因此引发了Cannot update a component while rendering a different component的警告。
可行方案
方案一:利用Grid API获取当前页数据,批量标记已读
通过MUI Data Grid的useGridApiRef获取表格实例,直接拿到当前页面的可见行数据,在组件挂载、分页切换等时机批量标记未读通知为已读,避免渲染阶段更新状态。
import { DataGrid, useGridApiRef } from '@mui/x-data-grid'; import { useState, useEffect } from 'react'; function Notifications() { const apiRef = useGridApiRef(); const [unread, setUnread] = useState([]); // 存储未读通知ID const [notifications, setNotifications] = useState([]); // 所有通知数据 // 标记当前页未读通知为已读 const markCurrentPageUnreadAsRead = () => { if (!apiRef.current) return; // 获取当前页面可见的所有行 const visibleRows = apiRef.current.getVisibleRows(); // 筛选出当前页中未读的通知ID const currentPageUnreadIds = visibleRows .filter(row => unread.includes(row.id)) .map(row => row.id); // 更新未读列表,移除已标记的ID setUnread(prev => prev.filter(id => !currentPageUnreadIds.includes(id))); }; // 组件挂载时,自动标记当前页未读为已读 useEffect(() => { markCurrentPageUnreadAsRead(); }, [apiRef, unread, notifications]); // 分页切换时,标记新页面的未读通知 const handlePageChange = () => { markCurrentPageUnreadAsRead(); }; const columns = [ { field: "message", headerName: "Message", flex: 1, renderCell: (params) => ( // Message组件仅负责展示,状态由父组件传递 <Message row={params.row} isUnread={unread.includes(params.row.id)} /> ), }, // 其他列配置... ]; return ( <DataGrid apiRef={apiRef} rows={notifications} columns={columns} pagination onPageChange={handlePageChange} // 其他表格配置... /> ); }
方案二:监听通知进入视口,自动标记已读
如果需要实现“用户看到通知即标记为已读”的效果,可以用Intersection Observer监听Message组件是否进入视口,在回调中更新状态(同样避免渲染阶段操作)。
Message组件代码
import { useEffect, useRef } from 'react'; function Message({ row, onMarkAsRead }) { const messageRef = useRef(null); useEffect(() => { const observer = new IntersectionObserver( (entries) => { entries.forEach(entry => { // 当通知50%进入视口时,标记为已读 if (entry.isIntersecting) { onMarkAsRead(row.id); observer.unobserve(entry.target); // 仅标记一次 } }); }, { threshold: 0.5 } ); if (messageRef.current) { observer.observe(messageRef.current); } return () => { if (messageRef.current) { observer.unobserve(messageRef.current); } }; }, [row.id, onMarkAsRead]); return ( <div ref={messageRef} className={unread.includes(row.id) ? 'text-bold' : ''} > {row.message} </div> ); }
父组件中调用
// 父组件中定义标记函数 const handleMarkAsRead = (id) => { setUnread(prev => prev.filter(unreadId => unreadId !== id)); }; // 列配置中传递函数 const columns = [ { field: "message", headerName: "Message", flex: 1, renderCell: (params) => ( <Message row={params.row} onMarkAsRead={handleMarkAsRead} /> ), }, ];
内容的提问来源于stack exchange,提问作者Enzo
相关产品推荐
相关产品推荐

