解决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>
相关推荐
Never_Satisfied几秒前
在JavaScript / HTML / Node.js中,post方式的Content-Type属性的text的三种编码
javascript·node.js·html
C2X10 分钟前
Vue3.0 学习总结
前端
汤姆Tom12 分钟前
CSS 新特性与未来趋势
前端·css·面试
尘世中一位迷途小书童12 分钟前
🚀 pnpm + Monorepo 实战指南:现代前端项目管理的最佳实践
前端·架构
Never_Satisfied23 分钟前
在JavaScript / HTML中,Chrome报错Refused to execute inline script
javascript·chrome·html
杨超越luckly26 分钟前
HTML应用指南:利用GET请求获取全国中国建设银行网点位置信息
前端·arcgis·html·数据可视化·门店数据
王翼鹏28 分钟前
html 全角空格和半角空格
前端·html
敲代码的嘎仔28 分钟前
JavaWeb零基础学习Day2——JS & Vue
java·开发语言·前端·javascript·数据结构·学习·算法
CsharpDev-奶豆哥32 分钟前
jq获取html字符串中的图片逐个修改并覆盖原html的解决方案
前端·html
Keepreal4961 小时前
pdf文件预览实现
javascript·react.js