Material React Table列宽调整后滚动位置重置问题求助
解决Material React Table调整列宽后滚动位置重置问题
这个问题源于列宽调整触发表格重渲染时,虚拟滚动器的滚动位置未被保留,导致自动回到顶部。以下是具体解决步骤:
步骤1:添加滚动位置保存的Ref
新增一个Ref用于存储当前滚动到的起始行索引:
const savedScrollIndex = useRef<number>(0);
步骤2:监听滚动事件保存位置
在rowVirtualizerOptions中添加onScroll回调,实时记录当前滚动的起始索引:
rowVirtualizerOptions: { overscan: 5, onScroll: () => { const virtualizer = rowVirtualizerInstanceRef.current; if (virtualizer) { savedScrollIndex.current = virtualizer.getCurrentScrollPosition().startIndex; } }, },
步骤3:监听列宽变化并恢复滚动位置
- 新增列宽状态管理:
const [columnSizing, setColumnSizing] = useState<MRT_ColumnSizingState>({});
- 在表格配置中绑定列宽变化事件和状态:
onColumnSizingChange: setColumnSizing, state: { isLoading, sorting, columnSizing },
- 添加
useEffect监听列宽变化,恢复滚动位置:
useEffect(() => { if (rowVirtualizerInstanceRef.current && savedScrollIndex.current > 0) { rowVirtualizerInstanceRef.current.scrollToIndex(savedScrollIndex.current); } }, [columnSizing]);
完整修改后的代码
import { useEffect, useMemo, useRef, useState } from 'react'; import { MaterialReactTable, useMaterialReactTable, type MRT_ColumnDef, type MRT_SortingState, type MRT_RowVirtualizer, type MRT_ColumnSizingState, } from 'material-react-table'; import { makeData, type Person } from './makeData'; const Example = () => { const columns = useMemo<MRT_ColumnDef<Person>[]>( () => [ { accessorKey: 'firstName', header: 'First Name', size: 150, }, { accessorKey: 'middleName', header: 'Middle Name', size: 170, }, { accessorKey: 'lastName', header: 'Last Name', size: 150, }, { accessorKey: 'email', header: 'Email Address', size: 300, }, { accessorKey: 'phoneNumber', header: 'Phone Number', size: 250, }, { accessorKey: 'address', header: 'Address', size: 300, }, { accessorKey: 'zipCode', header: 'Zip Code', }, { accessorKey: 'city', header: 'City', size: 220, }, { accessorKey: 'state', header: 'State', }, { accessorKey: 'country', header: 'Country', size: 350, }, { accessorKey: 'petName', header: 'Pet Name', }, { accessorKey: 'age', header: 'Age', }, { accessorKey: 'salary', header: 'Salary', }, { accessorKey: 'dateOfBirth', header: 'Date of Birth', }, { accessorKey: 'dateOfJoining', header: 'Date of Joining', }, { accessorKey: 'isActive', header: 'Is Active', }, ], [], ); const rowVirtualizerInstanceRef = useRef<MRT_RowVirtualizer>(null); const savedScrollIndex = useRef<number>(0); // 保存滚动索引 const [data, setData] = useState<Person[]>([]); const [isLoading, setIsLoading] = useState(true); const [sorting, setSorting] = useState<MRT_SortingState>([]); const [columnSizing, setColumnSizing] = useState<MRT_ColumnSizingState>({}); // 列宽state useEffect(() => { if (typeof window !== 'undefined') { setData(makeData(10_000)); setIsLoading(false); } }, []); useEffect(() => { // 排序变化时滚动到顶部 try { rowVirtualizerInstanceRef.current?.scrollToIndex?.(0); savedScrollIndex.current = 0; // 重置保存的索引 } catch (error) { console.error(error); } }, [sorting]); // 列宽变化后恢复滚动位置 useEffect(() => { if (rowVirtualizerInstanceRef.current && savedScrollIndex.current > 0) { rowVirtualizerInstanceRef.current.scrollToIndex(savedScrollIndex.current); } }, [columnSizing]); const table = useMaterialReactTable({ columns, data, defaultDisplayColumn: { enableResizing: true }, enableBottomToolbar: false, enableColumnResizing: true, enableColumnVirtualization: true, enableGlobalFilterModes: true, enablePagination: false, enableColumnPinning: true, enableRowNumbers: true, enableRowVirtualization: true, muiTableContainerProps: { sx: { maxHeight: '600px' } }, onSortingChange: setSorting, onColumnSizingChange: setColumnSizing, // 监听列宽变化 state: { isLoading, sorting, columnSizing }, rowVirtualizerInstanceRef, rowVirtualizerOptions: { overscan: 5, onScroll: () => { // 实时保存当前滚动起始索引 const virtualizer = rowVirtualizerInstanceRef.current; if (virtualizer) { savedScrollIndex.current = virtualizer.getCurrentScrollPosition().startIndex; } }, }, columnVirtualizerOptions: { overscan: 2 }, }); return <MaterialReactTable table={table} />; }; export default Example;
原理说明
- 通过虚拟滚动器的
onScroll事件实时记录当前滚动的起始行索引 - 监听列宽变化状态,在列宽调整完成后调用
scrollToIndex恢复之前的滚动位置 - 保留了原有排序后滚动到顶部的逻辑,同时避免列宽调整时干扰滚动位置
内容的提问来源于stack exchange,提问作者Maria Avanova
相关产品推荐
相关产品推荐

