解决antd TreeSelect 返回值不包含父节点问题 -自定义组件(react)

在写一个表单时使用了antd的 TreeSelect,在对TreeSelect的值提交时发现,父节点的值在半选状态时未提交,在选中状态时(子节点全选),子节点不提交,只提交父节点,这与后端需求不符,后端要求提交全部的节点,所有手动改造了一下,以适应需求,组件代码如下:

TypeScript 复制代码
import { TreeSelect } from "antd";
import React, { useState, useEffect } from "react";

export type FromTreeItem = {
    key?: number | string;
    title?: string;
    parentKey?: number | string;
    value?: number | string;
    children?: FromTreeItem[];
};

export type FromTreeSelectProps = {
    value?: any;
    treeData?: FromTreeItem[];
    onChange?: (value: any) => void;
};

/**  
 * 解决antd TreeSelect 返回值不包含父节点问题  
 * @param props   
 * @returns   
 */
const FromTreeSelect: React.FC<FromTreeSelectProps> = (props) => {
    const [selectedKeys, setSelectedKeys] = useState<(string | number)[]>([]);
    const [treeDataMap, setTreeDataMap] = useState<Record<string | number, FromTreeItem>>({});


    const treeToMap = (tree: FromTreeItem[]): Record<string | number, FromTreeItem> => {
        const map: Record<string | number, FromTreeItem> = {};
        const traverse = (nodes: FromTreeItem[]) => {
            nodes.forEach(node => {
                node.key ? map[node.key] = node : null; // 将当前节点添加到映射中  
                if (node.children) {
                    traverse(node.children); // 递归遍历子节点  
                }
            });
        };
        traverse(tree); // 从根节点开始遍历  
        return map;
    };
    useEffect(() => {
        if (props.treeData)
            setTreeDataMap(treeToMap(props.treeData))
    }, [props.treeData]);

    useEffect(() => {
        // 初始化 selectedKeys  
        if (props.value && treeDataMap) {
            setSelectedKeys(getAllChildrenKey(props.value));
        }
    }, [treeDataMap, props.value]);

    /**  
     * 根据选中的key找到所有父节点key并一起返回  
     * @param selectKeys   
     */
    const getAllNodeKey = (selectKeys: (string | number)[]): (string | number)[] => {
        const allKeys = new Set<string | number>(selectKeys);;
        const traverse = (node: FromTreeItem) => {
            if (node.parentKey) {
                allKeys.add(node.parentKey)
                traverse(treeDataMap[node.parentKey])
            }
        };
        selectKeys.forEach(key => {
            traverse(treeDataMap[key])
        });
        return Array.from(allKeys);
    };

    /**  
     * 根据给定的值 ,找到给定节点是否选中了子节点,如选中了子节点,则删除当前节点
     * @param keys   
     * @param tree   
     */
    const getAllChildrenKey = (keys: (string | number)[]): (string | number)[] => {
        if (!keys)
            return []
        const allKeys = new Set<string | number>(keys);
        keys.forEach(key => {
            const node: FromTreeItem = treeDataMap[key];
            if (node.children) {
                node.children.forEach((child) => {
                    if (node.key && allKeys.has(node.key) && child.key && allKeys.has(child.key)) {
                        allKeys.delete(node.key)
                    }
                });
            }
        })
        return Array.from(allKeys);
    };

    const handleChange = (newKeys: (string | number)[]) => {
        setSelectedKeys(newKeys);
        if (props.onChange) {
            props.onChange(getAllNodeKey(newKeys));
        }
    };

    const { SHOW_ALL } = TreeSelect;
    return (
        <TreeSelect
            treeCheckable
            treeData={props.treeData}
            value={selectedKeys}
            onChange={handleChange}
            showCheckedStrategy={SHOW_ALL}
        />
    );
};

export default FromTreeSelect;

使用方式同antd的其他组件,如:

TypeScript 复制代码
 <Form.Item
            name={'menuIds'}
            label={'菜单'}
            rules={[{ required: true }]}
          >
            <FromTreeSelect treeData={menuTreeData} />
          </Form.Item>
相关推荐
w_y_fan11 小时前
flutter_native_splash: ^2.4.7
android·前端·flutter
穿花云烛展11 小时前
项目实战4:奇思妙想console
前端
穿花云烛展11 小时前
项目实践3:一个冲突引起的灾难
前端·github
代码小学僧11 小时前
windows 电脑解决 Figma 提示 PingFang font missing 问题
前端·设计师
Asort11 小时前
JavaScript设计模式(十九)——观察者模式 (Observer)
前端·javascript·设计模式
Sherry00711 小时前
【译】 CSS 布局算法揭秘:一次思维转变,让 CSS 从玄学到科学
前端·css
老前端的功夫11 小时前
虚拟列表:拯救你的万级数据表格
前端
colorFocus11 小时前
vue在页面退出前别忘记做好这些清理工作
前端·vue.js
星链引擎11 小时前
4sapi生成式 AI 驱动下的智能聊天机器人
前端
前端赵哈哈11 小时前
Git 本地仓库操作指南:将未提交文件复刻至新分支(无需关联远端)
前端·git·github