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

如何在Ant Design表格移除列时自动清除对应过滤器?

问题

我在基于ReactJS(TypeScript)、使用Ant Design 4.12.2的项目中,实现了一个展示多条记录数据的表格,支持通过带树形选项的弹出框添加或移除列,部分列带有过滤器功能。

目前功能整体正常,但存在以下问题:激活某列的过滤器后移除该列,列会被成功移除,但对应的过滤器并未失效,表格显示的记录数无法恢复到过滤前的状态;重新添加该列时,之前激活的过滤器仍处于生效状态。

我曾尝试在useEffect中将列的filteredValue设为null,但没有效果;用于调试的clear按钮仅在列可见时能清除过滤器,列移除后该按钮无效,重新添加列时过滤器状态也存在异常。

编辑:我已参考相关文章更新代码,加入了对filteredInfo的跟踪与更新,但问题依旧存在。

代码示例

const isPresent = <T,>(t: T | undefined | null): t is T => t != null;

interface User {
    username: string,
    status: string
}

const ReportItemsTable: React.FC = () => {
    const allColumnOptions = [
        {
            key: "username", title: "Username"
        },
        {
            key: "status", title: "Status"
        }
    ];

    const items: User[] = [
        {
            status: "one",
            username: "Piet"
        },
        {
            status: "two",
            username: "Saar"
        },
        {
            status: "one",
            username: "Jan"
        },
        {
            status: "two",
            username: "Klaas"
        },
        {
            status: "one",
            username: "Maartje"
        },
        {
            status: "three",
            username: "Sjeng"
        },
        {
            status: "one",
            username: "Elke"
        },
        {
            status: "two",
            username: "Twan"
        },
        {
            status: "one",
            username: "An"
        },
        {
            status: "three",
            username: "Nel"
        },
    ];

    const [filteredInfo, setFilteredInfo] = useState<Record<string, FilterValue | null>>({});


    const possibleColumns: ColumnType<User>[] = [
        {
            title: "Username",
            key: "username",
            dataIndex: "username",
            sorter: (a: User, b: User) => a.username.localeCompare(b.username),
            render: (userName: string) => (<>{userName}</>)
        },
        {
            title: "Status",
            key: "status",
            dataIndex: "status",
            filteredValue: filteredInfo && filteredInfo["status"],
            filters: [
                {
                    text: "One",
                    value: "one"
                },
                {
                    text: "Two",
                    value: "two"
                },
                {
                    text: "Three",
                    value: "three"
                },
            ],
            onFilter: (value: ColumnFilterValue, user: User) => user.status === value,
            sorter: (a: User, b: User) => a.status.localeCompare(b.status),
            render: (status: string) => (<>{status}</>)
        }
    ];

    // Note that selectedColumns is controlled by checkedKeys. selectedColumns should not be modified directly.
    const [checkedKeys, setCheckedKeys] = useState<Key[] | { checked: Key[]; halfChecked: Key[]; }>([]);
    const [selectedColumns, setSelectedColumns] = useState<ColumnType<User>[]>(possibleColumns);

    const getTreeData = (allOptions: DataNode[]): DataNode[] => {
        return [{
            key: "masterKey",
            title: "(de)select all",
            children: [...allOptions]
        }];
    };

    // The useEffect below was originally only in charge of checking 
    // whether the checkedKeys had changed and accordingly adding or 
    // removing columns from the table. It was expanded to set the 
    // filteredValue to null if the column was unchecked. 
    useEffect(() => {
        setFilteredInfo(filteredInfo => {
            const newFilteredInfo = {...filteredInfo};
            const visibleKeys = Array.isArray(checkedKeys) ? checkedKeys : checkedKeys.checked;
            const invisibleKeys = possibleColumns.map(column => column.key).filter(isPresent).filter(columnKey => !visibleKeys.includes(columnKey));
            invisibleKeys.forEach(key => delete newFilteredInfo[key]);
            return newFilteredInfo;
        });

        if (Array.isArray(checkedKeys)) {
            setSelectedColumns(possibleColumns
                .map(column => {
                    if (!isPresent(column.key)) return column;
                    if (!checkedKeys.includes(column.key)) {
                        return {
                            ...column,
                            filteredValue: null
                        }
                    }
                    return column;
                })
                .filter(column => checkedKeys
                    .map(checkedKey => checkedKey.toString())
                    .includes(column.key?.toString() ?? "")));
        } else {
            setSelectedColumns(possibleColumns
                .map(column => {
                    if (!isPresent(column.key)) return column;
                    if (!checkedKeys.checked.includes(column.key)) {
                        return {
                            ...column,
                            filteredValue: null
                        }
                    }
                    return column;
                })
                .filter(column => checkedKeys.checked
                    .map(checkedKey => checkedKey.toString())
                    .includes(column.key?.toString() ?? "")));
        }
    }, [checkedKeys]);

    const filterTree =
        <Tree
            key={"columnfilter"}
            checkable
            defaultExpandedKeys={["masterKey"]}
            checkedKeys={checkedKeys}
            selectable={false}
            onCheck={checkedKeys => {
                setCheckedKeys(checkedKeys);
            }}
            treeData={getTreeData(allColumnOptions)}
        />
    ;

    const columnFilterButton =
        <Popover
            placement="bottom"
            title="Select columns"
            content={filterTree}
            trigger="click">
            <Tooltip title="Select columns">
                <Button icon={<ViewWeekOutlinedIcon sx={{ fontSize: 17, marginTop: "2.5px" }}></ViewWeekOutlinedIcon>}>
                </Button>
            </Tooltip>
        </Popover>
    ;

    return (
        <>
            <Row style={{paddingTop: "10px", paddingBottom: "10px"}}>
                <Col span={24} style={{ textAlign: "left" }}>
                    <Space>
                        <Button.Group>
                            {columnFilterButton}
                        </Button.Group>
                    </Space>
                </Col>
            </Row>
            <Table
                onChange={(pagination, filters) => setFilteredInfo(filters)}
                columns={selectedColumns}
                dataSource={items}
                size="middle"
            />
            <button onClick={() => {
                setFilteredInfo({});

                setSelectedColumns(selectedColumns.map(column => {
                    return {
                        ...column,
                        filteredValue: null
                    };
                }));
            }
            }>clear</button>
        </>
    );
};

export default ReportItemsTable;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:01:44