React+TypeScript+MUI双DataGrid页面刷新后状态同步与持久化问题
双DataGrid双向联动与LocalStorage状态持久化解决方案
问题核心
- 两个DataGrid需双向同步选中状态:全量Grid选中的行进入收藏Grid,收藏Grid取消选中的行同步从全量Grid移除
- 页面刷新后状态丢失,且出现
Warning: Cannot update a component (PeopleTables) while rendering a different component (ForwardRef(DataGrid))警告
关键修复点
1. 统一状态管理
用单一状态变量存储收藏行ID,作为两个DataGrid的状态源,避免多状态源导致的不一致。
2. 正确的LocalStorage同步逻辑
- 组件初始化时从LocalStorage读取历史状态作为初始值
- 用
useEffect监听状态变化,异步写入LocalStorage,避免渲染阶段触发状态更新
3. 消除跨组件更新警告
所有状态更新必须放在事件回调或useEffect中,禁止在组件渲染过程中直接调用setState。
完整代码示例
import { useState, useEffect } from 'react'; import { DataGrid, GridRowSelectionModel } from '@mui/x-data-grid'; // 行数据类型定义 interface Person { id: number; name: string; // 可添加其他业务字段 } // LocalStorage存储键名 const FAVORITE_STORAGE_KEY = 'favorite-person-ids'; const PeopleTables = () => { // 从LocalStorage加载初始收藏ID,默认空数组 const initialFavorites = JSON.parse( localStorage.getItem(FAVORITE_STORAGE_KEY) || '[]' ) as GridRowSelectionModel; // 统一管理收藏ID状态 const [favoriteIds, setFavoriteIds] = useState<GridRowSelectionModel>(initialFavorites); // 全量数据源示例 const fullDataset: Person[] = [ { id: 1, name: '张三' }, { id: 2, name: '李四' }, { id: 3, name: '王五' }, { id: 4, name: '赵六' }, ]; // 动态生成收藏数据源:过滤全量数据中属于收藏的行 const favoriteDataset = fullDataset.filter(person => favoriteIds.includes(person.id)); // 状态变化时同步到LocalStorage useEffect(() => { localStorage.setItem(FAVORITE_STORAGE_KEY, JSON.stringify(favoriteIds)); }, [favoriteIds]); // 处理全量Grid的选中事件:合并新选中的行到收藏列表 const handleFullGridSelection = (newSelection: GridRowSelectionModel) => { // 去重合并,避免重复ID const updatedFavorites = [...new Set([...favoriteIds, ...newSelection])]; setFavoriteIds(updatedFavorites); }; // 处理收藏Grid的选中事件:移除取消选中的行 const handleFavoriteGridSelection = (newSelection: GridRowSelectionModel) => { // 仅保留仍处于选中状态的ID const updatedFavorites = favoriteIds.filter(id => newSelection.includes(id)); setFavoriteIds(updatedFavorites); }; return ( <div style={{ display: 'flex', gap: '24px', padding: '24px' }}> <div style={{ width: 500 }}> <h3>全量数据列表</h3> <DataGrid rows={fullDataset} columns={[ { field: 'id', headerName: 'ID', width: 70 }, { field: 'name', headerName: '姓名', flex: 1 }, ]} checkboxSelection rowSelectionModel={favoriteIds} onRowSelectionModelChange={handleFullGridSelection} /> </div> <div style={{ width: 500 }}> <h3>收藏列表</h3> <DataGrid rows={favoriteDataset} columns={[ { field: 'id', headerName: 'ID', width: 70 }, { field: 'name', headerName: '姓名', flex: 1 }, ]} checkboxSelection // 仅同步当前收藏数据中存在的ID,避免无效选中 rowSelectionModel={favoriteIds.filter(id => favoriteDataset.some(p => p.id === id))} onRowSelectionModelChange={handleFavoriteGridSelection} /> </div> </div> ); }; export default PeopleTables;
代码说明
- 单一状态源:
favoriteIds同时控制两个Grid的选中状态,确保双向同步一致 - LocalStorage同步:通过
useEffect异步写入,避免渲染阶段的状态更新冲突 - 收藏Grid选中过滤:只同步当前收藏数据中存在的ID,防止出现无效选中状态
- 事件驱动更新:所有状态更新都由用户选中事件触发,消除跨组件渲染更新的警告
内容的提问来源于stack exchange,提问作者Cristianolm
相关产品推荐
相关产品推荐

