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

Fluent UI React:DetailsList的onSelectionChanged不触发及分页选中专属问题

问题描述

我实现了自定义分页功能,需求是分页切换时保留选中状态——用户在第1页选中项1,切换到第2页再切回第1页时,项1需保持选中。但目前选中/取消选中项时,onSelectionChanged事件始终不触发,调试器仅在加载时触发一次,后续操作无响应。相关代码如下:

const RelationalDataList: React.FC<IRelationalDataListProps> = (props) => {
//...
const handleSelectionChanged = () => {
        debugger;
    };

useEffect(() => {
    setSelection(() => {
        // TRY WITH NEW SELECTION ??
        if (!selectionProps) {
            return undefined;
        }
        const sel = new Selection({
            selectionMode: selectionProps.selectMultiple ? SelectionMode.multiple : SelectionMode.single,
            onSelectionChanged: handleSelectionChanged,
            canSelectItem: () => { return true; },
            items: [...list],
            getKey: (item) => {
                return item[getPrimaryKeyName(entityDefinition)];
            },
            onItemsChanged: () => { }

        });
        
        selectionProps.selectedIds.forEach((selectedId) => {
            sel.setKeySelected(selectedId, true, false);
        });

        return sel;
    });
}, []); // only one instance

  //somewhere down the line:

   
const listComponent = useMemo(() => {
    const listElement = <DetailsList
        selectionMode={selectionProps ? (selectionProps.selectMultiple ? SelectionMode.multiple : SelectionMode.single) : SelectionMode.none}
        items={list}
        columns={columns}
        selection={selection}
        selectionPreservedOnEmptyClick={true}
        getKey={(item) => { return item[pkPropName]; }}
        layoutMode={DetailsListLayoutMode.fixedColumns}
        onRenderCheckbox={(defaultProps, defaultRender) => {
            return <Stack styles={{
                root: {
                    paddingTop: '11px'
                }
            }}>{defaultRender && defaultRender(defaultProps)}</Stack>;
        }}
        styles={...}

    />;

    if (!maxHeight) {
        return <AutoSizer>
            {({ height, width }) => {
                return <Stack className='list-sizer' styles={{
                    root: {
                        height,
                        width
                    }
                }}>
                    {listElement}
                </Stack>;
            }}
        </AutoSizer>;
    }

    return listElement;
}, [selectionProps, list, columns, selection, maxHeight, pkPropName]);
解决方案

核心问题分析

  1. Selection实例仅初始化一次:useEffect依赖为空数组,组件挂载后只会创建一次Selection实例,分页切换时list(当前页数据)更新,但旧实例绑定的还是初始页的items,导致事件无法触发。
  2. 选中状态未全局同步:当前代码没有把选中状态同步到父组件,分页切换后无法保留跨页的选中记录。

1. 让Selection实例随分页更新

修改useEffect的依赖项,把list和selectionProps加进去,这样分页切换或选中配置变化时,重新创建绑定当前页数据的Selection实例:

useEffect(() => {
    if (!selectionProps) {
        setSelection(undefined);
        return;
    }
    const sel = new Selection({
        selectionMode: selectionProps.selectMultiple ? SelectionMode.multiple : SelectionMode.single,
        onSelectionChanged: handleSelectionChanged,
        canSelectItem: () => true,
        items: [...list],
        getKey: (item) => item[getPrimaryKeyName(entityDefinition)],
        onItemsChanged: () => {}
    });
    
    // 只标记当前页中已被选中的项
    const currentPageSelectedIds = selectionProps.selectedIds.filter(id => 
        list.some(item => item[getPrimaryKeyName(entityDefinition)] === id)
    );
    currentPageSelectedIds.forEach((selectedId) => {
        sel.setKeySelected(selectedId, true, false);
    });

    setSelection(sel);
}, [list, selectionProps]); // 依赖更新时重建实例

2. 同步选中状态到父组件

在handleSelectionChanged中,把当前选中的ID集合传递给父组件保存,这样跨页切换时能保留所有选中记录:

const handleSelectionChanged = () => {
    debugger;
    // 获取当前所有选中的key
    const selectedKeys = selection?.getSelectedKeys() || new Set();
    // 调用父组件的回调更新全局选中ID
    selectionProps.onSelectedIdsChanged?.(Array.from(selectedKeys));
};

注意:需要确保IRelationalDataListProps定义了onSelectedIdsChanged回调,用于父组件接收选中状态。

3. 确认DetailsList绑定最新实例

listComponent的useMemo已经包含selection作为依赖,这部分不用改,确保Selection实例更新时,DetailsList能重新渲染并绑定新实例。

4. 父组件维护全局选中状态

父组件需要保存一个全局的selectedIds数组,当子组件(RelationalDataList)触发onSelectedIdsChanged时更新这个数组,分页切换时把这个数组传给子组件的selectedIds属性,就能实现跨页保留选中状态。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 14:37:24