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

如何在MUI X Data Grid搜索/筛选时保留行选中状态

解决MUI X DataGrid筛选/搜索后选中状态丢失问题

问题背景

使用MUI X DataGrid展示文章列表,支持单行/多行选中,已实现自定义搜索和筛选功能,但执行搜索或筛选操作后,之前的选中状态会丢失——原因是筛选后不在结果集中的选中行被自动取消选中。

解决方案核心思路

不再仅依赖当前展示的行维护选中状态,而是在父组件维护一个全局的选中ID集合,这个集合不受筛选/搜索操作影响。筛选后DataGrid只需要渲染当前结果集中的选中项,但全局选中ID保留所有已选记录,恢复筛选时自动还原所有选中状态。

修改步骤及代码调整

1. 父组件SelectArticle修改

添加全局选中ID状态,传递给子组件用于同步:

import * as React from 'react';
import { Paper } from '@mui/material';

import { FilterArticle } from './FilterArticle';
import { SearchArticle } from './SearchArticle';
import { useDispatch } from 'react-redux';
import { setActualTitle } from 'feature/title.slice';
import { SelectionArticle } from './SelectionArticle';

export const SelectArticle = ({ control, watch, register, setValue }) => {
 const list = [
    {
      id: 1,
      name: 'Snow',
      age: 35,
      stack: '3',
      service: '1',
      asset: '1',
      price: [{ SSL: 5 }, { SSB: 10 }, { SSF: 15 }],
      quantity: 5,
    },
    {
      id: 2,
      name: 'Lannister',
      age: 42,
      stack: '3',
      service: '1',
      asset: '2',
      price: [{ SSL: 5 }, { SSB: 10 }, { SSF: 15 }],
      quantity: 5,
    },
    {
      id: 3,
      name: 'Lannister',
      age: 45,
      stack: '3',
      service: '1',
      asset: '3',
      price: [{ SSL: 5 }, { SSB: 10 }, { SSF: 15 }],
      quantity: 5,
    },
  ];

  const dispatch = useDispatch();
  const [rows, setRows] = React.useState(list);
  // 新增:维护全局选中ID集合
  const [selectedRowIds, setSelectedRowIds] = React.useState([]);

  React.useEffect(() => {
    dispatch(setActualTitle('Articles professional services'));
   }, []);

  return (
    <div className="form">
      <label className="subtitle">Select Articles</label>{' '}
        <Paper className="form_group" style={{ height: 550, width: '60vw' }}>
          <FilterArticle
            setRows={setRows}
            watch={watch}
            list={list}
            register={register}
          />
          <SearchArticle setRows={setRows} list={list} />

          <SelectionArticle
            list={list}
            setValue={setValue}
            control={control}
            rows={rows}
            watch={watch}
            // 传递全局选中状态及更新方法
            selectedRowIds={selectedRowIds}
            setSelectedRowIds={setSelectedRowIds}
          />
        </Paper>
      
    </div>
  );
};

2. 选择组件SelectionArticle修改

基于全局选中ID更新DataGrid的选中状态,同时同步react-hook-form的字段值:

import { DataGrid } from '@mui/x-data-grid';
import React, { useEffect } from 'react';
import { Stack } from 'react-bootstrap';
import { useFieldArray } from 'react-hook-form';

export const SelectionArticle = ({ control, setValue, rows, watch, selectedRowIds, setSelectedRowIds }) => {
  const entityConcerned = watch('OffersInfos.entityConcerned');
  const { replace } = useFieldArray({
    control,
    name: 'Articles',
  });

  // 从全局选中ID获取当前展示行中的选中项,用于DataGrid的selectionModel
  const selectionModel = rows.filter(row => selectedRowIds.includes(row.id)).map(row => row.id);

  // 当全局选中ID变化时,同步更新react-hook-form的Articles字段
  useEffect(() => {
    const selectedArticles = selectedRowIds.map(id => rows.find(row => row.id === id)).filter(Boolean);
    replace(selectedArticles);
  }, [selectedRowIds, rows, replace]);

  const columns = [
    { field: 'id', headerName: 'ID', width: 70 },
    { field: 'name', headerName: 'name', width: 130 },
    {
      field: 'age',
      headerName: 'Age',
      type: 'number',
      width: 90,
    },
    {
      field: 'stack',
      headerName: 'Stacks',
      width: 90,
    },
    {
      field: 'service',
      headerName: 'service',
      width: 90,
    },
    {
      field: 'asset',
      headerName: 'asset',
      width: 90,
    },
    {
      field: 'quantity',
      headerName: 'quantity',
      width: 90,
    },
    {
      field: 'price',
      headerName: 'price',
      width: 90,
      renderCell: (params) => {
        const priceObj = params.row.price.find((obj) => obj[entityConcerned]);
        const price = priceObj ? priceObj[entityConcerned] : '';

        return <span>{price}</span>;
      },
    },
  ];

  const onRowsSelectionHandler = (ids) => {
    // 更新全局选中ID集合
    setSelectedRowIds(ids);
  };

  function NoRowsOverlay() {
    return (
      <Stack height="100%" alignItems="center" justifyContent="center">
        Aucun article
      </Stack>
    );
  }
  function NoResultsOverlay() {
    return (
      <Stack height="100%" alignItems="center" justifyContent="center">
        Aucun résultat
      </Stack>
    );
  }

  return (
    <DataGrid
      rows={rows}
      getRowId={(row) => row?.id}
      columns={columns}
      checkboxSelection
      components={{ NoRowsOverlay, NoResultsOverlay }}
      componentsProps={{
        pagination: {
          labelRowsPerPage: 'Articles/page',
          rowsPerPageOptions: [5, 10, 20, 50, 100],
        },
      }}
      onSelectionModelChange={(ids) => {
        onRowsSelectionHandler(ids);
      }}
      selectionModel={selectionModel}  
    />
  );
};

原理说明

  • 父组件的selectedRowIds存储所有被选中行的ID,不受筛选/搜索影响,即使行不在当前展示列表中,ID也会被保留。
  • DataGrid的selectionModel只渲染当前展示行中属于selectedRowIds的项,这样筛选后仍能看到当前结果里的选中状态。
  • 当筛选/搜索取消后,所有之前选中的行(包括原本不在结果集的)会重新显示,并且选中状态自动恢复。

内容的提问来源于stack exchange,提问作者Elodie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:52:04