React antd 4.x 异步加载treeSelect 返显

使用antd4.x treeSelect 异步加载要做到显示保存其实很简单,返显需要一些处理才能实现

首先需要使用到 treeExpandedKeys 展开属性, 在异步加载的treeSelect 使用 treeExpandedKeys 是能够触发 onLoad 事件,会自动调用接口去请求数据完成返显, 下面是基于我的业务部分实现, 有些参数是基于我自己的业务,自己甄别就好


 import React, {FC, useEffect, useState} from "react";
import _ from "lodash";
import {TreeSelect} from "antd";
import {history} from "@@/core/history";
import {getXiangYuTree} from "@/components/Editor/components/RightMenu/BasicInfo/CustomField/service";


//翔宇加载异步treeSelect
interface IProps {
    nowValue: any;
    item: any;
    changeValue: (value: string, code: string, type: string) => void
    extend: any[];
    replaceValue: any
    cid: string
}
const XYLoadTree: FC<IProps> = (props) => {
   const {nowValue, item, changeValue, extend, replaceValue, cid} = props
   const [treeData, setData] = useState([])
   const [parentId, setParentId] = useState(0)
   const [label, setLabel] = useState('')
   const [initState, setState] = useState(false)
   const [TreeExpand, setTreeExpand] = useState<string[]>(['0'])
   const [treeLoadedKeys, seTtreeLoadedKeys] = useState<string[]>([])
   const siteId = extend.find( item => item.code === "siteId" ).value
	// 判断是否叶子节点, 各有实现方式随意就好
    const isLeafs = (list) => {
        let treeList = [...list]
        for (let listElement of list) {
            listElement.isLeaf = !listElement.isParent
        }

        return treeList
    }

    // 初始化设置反显
    const initSetView = (treeList) => {
        //设置返显,找了一下文档可以使用antd的官网文档labelInValue 这个属性更好用,我这里有因为各种问题没去使用
        if (extend.find(item => item.code === 'columnId')?.label) {
            const label =  extend.find(item => item.code === 'columnId')?.label[0]
            const value =  extend.find(item => item.code === 'columnId')?.value
            const findValue = treeList.find( item => item.id === value[value.length -1] )
            // 是否需要反显
            setState(label?.length > 0 )
            // 是否点击在第一层
            if (findValue?.id) {
                setLabel(value)
            } else {
                setLabel(label)
            }

        }
    }
    // 请求接口后挂载节点antd Tree 组件提供的方法,很好用,tree结构异步加载的方式都可以用这个拼接数据
    const updateTreeData = (list: any, key: React.Key, children: any) => {
        return list.map((node: any) => {
            if (node.id === key) {
                return {
                    ...node,
                    children,
                };
            }
            if (node.children) {
                return {
                    ...node,
                    children: updateTreeData(node.children, key, children),
                };
            }
            return node;
        });
    };
    const onLoadData = ({id}) => {

       return new Promise(resolve => {

           getXiangYuTree(siteId, cid, id).then((res) => {

                if (res.success) {
                    const treeList = isLeafs(JSON.parse(replaceValue(res?.data)).Column)
                    setData(updateTreeData(treeData,id, treeList))
                    seTtreeLoadedKeys(treeList.filter( item => item.id ))
                    // setTreeExpand((old) => [...old, id])
                    //initState用户没有onChange && 当前加载的有没有要做反显的
                    const value =  extend.find(item => item.code === 'columnId')?.value
                    const findValue = treeList.find( item => item.id === value[value.length -1] )

                    if (findValue?.id) {
                        setLabel(value[value.length -1])
                    }

                    resolve(undefined);
                }
           })

       })
    }
	// 由于treeSelect 因为性能问题没有提供父节点访问路径,因此百度找了个方法,官网提供的方法在异步状态时并不好用,因此暴力算就好了此时不考虑性能
    function findParentIds(dataSource, nodeId) {
        const parentIds = []; // 用于存储所有父节点ID的数组

        // 定义一个递归函数,用于遍历整棵树并查找子节点的所有父节点
        function traverse(node, nodeId) {
            if (node.id === nodeId) { // 如果当前节点的ID等于子节点的ID,则表示已经找到了子节点,可以开始向上查找父节点
                return true; // 返回true表示已经找到了子节点
            }

            if (node?.children) { // 如果当前节点有子节点,则继续遍历子节点
                for (const childNode of node.children) {
                    if (traverse(childNode, nodeId)) { // 如果在子节点中找到了子节点的父节点,则将当前节点的ID添加到父节点ID数组中,并返回true表示已经找到了子节点
                        parentIds.push(node.id);
                        return true;
                    }
                }
            }

            return false; // 如果当前节点不是子节点的父节点,则返回false
        }

        // 从根节点开始遍历整棵树,并调用递归函数查找子节点的所有父节点
        for (const node of dataSource) {
            if (traverse(node, nodeId)) { // 如果在当前节点的子树中找到了子节点的父节点,则直接退出循环
                break;
            }
        }

        return parentIds; // 返回所有父节点ID的数组
    }

	
    const onChage = (value: string, label: string) => {
        //在onChange中获取父节点路径的value 或 id 用来给 treeExpandedKeys 做返显, 我这里是后端比较忙没有新加字段保存路径,因此自己做了一些处理
        const values = [...findParentIds(treeData, value)].reverse()
        values.push(value)
        setState(false);
        // 返给父组件数据,根据业务自己写就可以了
        changeValue(values, item.code, item.type, label)
        setTreeExpand([])
    }
	// 请求接口获取treeSelect数据
    useEffect(() => {
        getXiangYuTree(siteId, cid, parentId).then((res) => {
            const treeList = isLeafs(JSON.parse(replaceValue(res?.data))?.Column)

             seTtreeLoadedKeys(treeList.filter( item => item.id ))
            initSetView(treeList)
            setData(treeList || [])
        })

    }, [extend.find( item => item.code === "siteId" ).value])

    const onDropdownVisibleChange = (open) => {
             if (open) {
             	// 这里会有一个时差关系,如果不写个定时器就不会展开到目标节点,有懂原理的大佬请告知一下	
                 setTimeout(() => {
                     const value =  extend.find(item => item.code === 'columnId')?.value
                     const expand = value.slice(0, value.length-1)

                     setTreeExpand(expand)
                 }, 500)
             }
    }

    return  (
        <>
            <TreeSelect
                style={{ width: '100%' }}
                fieldNames={{value: 'id' , label: 'title'}}
                treeExpandedKeys={TreeExpand}
                value={ initState ? label : nowValue  }
                onTreeExpand={(keys) => {setTreeExpand(keys)}}
                dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
                loadData={onLoadData}
                treeData={treeData}
                placeholder={item.extend?.tips || ''}
                treeCheckable={item.extend.ifMulty === 'true'}
                onChange={(value, label) =>  onChage(value, label) }
                onDropdownVisibleChange={onDropdownVisibleChange}
                allowClear
            />
        </>
    )

}

export default XYLoadTree
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
React.js和Ant Design 4.x中,表单的提交可以通过使用Form组件的onFinish属性来实现。当表单中的所有表单项都通过验证时,onFinish事件会被触发,并且会将表单的值作为参数传递给事件处理函数。下面是一个简单的例子,展示了如何在React.js和Ant Design 4.x中提交表单。 首先,在你的代码中导入所需的模块: ```js import React, { useState } from 'react'; import { Form, Input, Button } from 'antd'; ``` 接下来,创建一个表单组件: ```js const MyForm = () => { // 定义表单项的值 const [form] = Form.useForm(); // 表单提交事件 const handleSubmit = (values) => { console.log('Received values of form: ', values); // 在这里可以提交表单数据到服务器 }; return ( <Form form={form} onFinish={handleSubmit}> <Form.Item label="Username" name="username" rules={[{ required: true, message: 'Please input your username!' }]}> <Input /> </Form.Item> <Form.Item label="Password" name="password" rules={[{ required: true, message: 'Please input your password!' }]}> <Input.Password /> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit"> Submit </Button> </Form.Item> </Form> ); }; ``` 在这个例子中,我们使用了Ant Design的Form、Input和Button组件来创建表单。在表单中,我们定义了一个onFinish事件处理函数handleSubmit,当表单中的所有表单项都通过验证时,该事件会被触发。在事件处理函数中,我们可以获取到表单的值,并将其提交到服务器。 最后,我们将表单组件渲染到页面中: ```js ReactDOM.render(<MyForm />, document.getElementById('root')); ``` 这是一个简单的例子,你可以根据自己的需求来添加更多的表单项和验证规则。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值