You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 01:03:30