treeSelect hook 实践

前言

antdtreeSelect 用起来没 element 的爽快,因为我们在实际使用的过程中,老感觉它少了什么东西。比如在使用 allowClear 的时候,找不到清空回调;比如在使用 showSearch 自定义搜索内容后没找到想要的结果,怎么重置 treeData; 问题很多,官方文档都没有给出对应的解决方案,很是令人头大。然而,经过一段时间摸索后,我发现其实这也许不是 antd 的问题,只是自己对react不够熟悉的问题,嗯,一切的问题都只是因为自己太菜了。

案例

今天突发奇想,把项目中自定义的 class 版本的 treeSelect组件用 hook 语法进行重写,会不会更好维护一些呢?那么上代码

功能点
  • 1、实现树状动态加载
  • 2、实现自定义查询功能
  • 3、无缝对接 Form
组件代码
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { TreeSelect } from 'antd';
import { debounce } from '@/utils';
import * as API from '@/axios/api';

const propTypes = {
  onChange: PropTypes.func,
  value: PropTypes.string,
};

/**
 * 转化节点
 * @param {Array} list
 * @param {Number} pid
 */
const format = (list, pid) => {
  return list.map(el => {
    return {
      pid,
      isLeaf: false,
      id: el.id,
      title: el.title,
      value: el.id,
    };
  });
};

/**
 * 深层递归插入子集
 * @param {Array} treeData
 * @param {String} pid
 * @param {Array} children
 */
function deepTree(treeData, pid, children) {
  treeData.forEach(item => {
    if (item.id === pid) {
      item.children = children;
      return;
    } else {
      item.children && item.children.length > 0 && deepTree(item.children, pid, children);
    }
  });
}

/**
 * 类别 
 * 树状下拉选择组件 *
 */
const MyTreeSelect = React.forwardRef((props, ref) => {
  const [treeData, setTreeData] = useState([]);
  const [treeDataCopy, setTreeDataCopy] = useState([]); // 备份数据
  const [value, setValue] = useState(undefined);

  // 初次请求
  useEffect(() => {
    getData();
  }, []);

  // 监听value变化
  useEffect(() => {
    // 如果没有选择
    if (value === undefined && treeData === treeDataCopy) {
      setTreeData(treeDataCopy);
    }
  }, [value]);

  // 监听props.value变化
  useEffect(() => {
    if (props.value !== value) {
      setValue(props.value);
    }
  }, [props.value]);

  /**
   * 请求函数 *
   */
  // 根据id获取数据,id为0时取顶层数据
  async function getData(pid = 0) {
    let res = await API.getData({ pid });
    if (res.code !== '200' || !res.data) {
      return false;
    }
    let list = format(res.data, pid);

    // 为0时初次加载;否则就是展开加载
    if (pid === 0) {
      setTreeData(list);
      setTreeDataCopy(list);
    } else {
      // 展开时的加载
      let treeDataList = [...treeData];
      deepTree(treeDataList, pid, [...list]);
      setTreeData(treeDataList);
      setTreeDataCopy(treeDataList);
    }
  }

  /**
   * 功能函数 *
   */
  // 展开加载数据;注意:此处的展开函数必须返回一个promise异步函数
  function onLoadData(treeNode) {
    const { id } = treeNode.props;
    // 用return才有加载效果
    return getData(id);
  }

  // 搜索防抖
  const debounceFn = debounce(e => {
    // 当输入有值时,进行搜索查询;否则重置 treeData
    if (e) {
      // 每次搜索时,清空已选中的选项,以防搜索结果没有选中值而出现显示bug
      handleOnChange(undefined);
      // 搜索结果; 此处也可以写你的异步请求
      setTreeData([]);
    }  
  }, 500);

  // 搜索
  function handleOnSearch(e) {
    debounceFn(e);
  }

  // 选择选项
  function handleOnChange(e) {
    props.onChange && props.onChange(e);
  }

  // 展开下拉框
  function handleOnDropdownVisibleChange(e) {
    // 当关闭下拉框且 treeData 数据为空时,重置 treeData
    if (!e && treeData.length === 0) {
      setTreeData(treeDataCopy);
    }
  }

  return (
    <TreeSelect
      showSearch
      allowClear
      treeDataSimpleMode
      ref={ref}
      value={value}
      treeData={treeData}
      loadData={onLoadData}
      onSearch={handleOnSearch}
      onChange={handleOnChange}
      onDropdownVisibleChange={handleOnDropdownVisibleChange}
      placeholder="请选择案件类别"
      searchPlaceholder="请输入关键字"
      dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
    />
  );
});

MyTreeSelect.propTypes = propTypes;

export default React.memo(MyTreeSelect);

使用
  <FormItem label="类别">
  	{getFieldDecorator('type')(<MyTreeSelect />)}
  </FormItem>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值