index.tsx 3.09 KB
import React from 'react';
import SelectPaging from './selectPaging';
import type { SelectProps } from 'antd';
import { Select } from 'antd';
import {
  isValue,
} from './utils';

export type { MySelectPagingProps } from './selectPaging';

const { Option } = Select;

export interface MySelectProps extends SelectProps<any> {
  onChildError?: (value: string[], list: any[]) => void; // 当前数据源未匹配时触发
  onSearchProt?: (val: string) => void;  // select 原生 onSearch 事件
}

/**
 * 业务封装
 * 修改1: value, onChange 状态被接管,不展示未匹配id内容展示
 * 修改2: onSearch 减少onSearch 触发频率
 */
class MySelect extends React.Component<MySelectProps> {
  static Option = Option;
  static Paging = SelectPaging;

  state = {
    initiate: true,
    initError: true,    // 是否抛出错误
    value: undefined,
  };
  timer: any = undefined; // 时间卡控

  constructor(props: MySelectProps) {
    super(props);
    this.onMyChange = this.onMyChange.bind(this);
    this.onMySearch = this.onMySearch.bind(this);
  }

  /**
   * 拦截初始值内容  如果内容不存在下拉菜单中 则重置表单
   */
  static getDerivedStateFromProps(props: any, state: any) {
    const { value } = props;
    if (state.initiate && value) {
      const children: any = props.children || [];

      if (value && children.length) {
        const { list, error } = isValue(value, children);
        if (!error.length) {
          return {
            value,
          };
        }
        if (props.onChildError && state.initError) {
          props.onChildError(error, props.children);
        }
        // 多选[multiple] 模式下可能存在部分匹配的情况
        if (list.length) {
          return {
            value: list,
            initError: false,
          }
        }
        return {
          initError: false,
        };
        
      }
    } else {
      if (props.value === undefined && props.value !== state.value) {
        // 业务需求, 重置同时更新下拉选择列表
        if (props.onSearch) props.onSearch();
      }
      return {
        value: props.value,
      };
    }
    return null;
  }

  onMyChange(value: any, option: any) {
    if (this.state.initiate) {
      this.setState(() => {
        return {
          initiate: false,
        };
      });
    }
    if (this.props.onChange) this.props.onChange(value, option || {});
  }

  onMySearch(value: string) {
    const { onSearch, onSearchProt } = this.props;
    // eslint-disable-next-line @typescript-eslint/no-unused-expressions
    onSearchProt && onSearchProt(value);
    if (this.timer) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(() => {
      // eslint-disable-next-line @typescript-eslint/no-unused-expressions
      onSearch && onSearch(value);
    }, 300);
  }

  render() {
    return (
      <Select
        allowClear
        showSearch
        optionFilterProp="children"
        {...this.props}
        onChange={this.onMyChange}
        onSearch={this.onMySearch}
        value={this.state.value}
      ></Select>
    );
  }
}

export default MySelect;