React DebounceSelect 组件 自用
2023-04-12 本文已影响0人
很好就这样吧
原生属性的继承
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
原生属性的重写
// 代表继承除type外,所有的input属性
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>,'type'> {
type: InputType
}
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { Select, Spin } from 'antd'
import type { SelectProps } from 'antd/es/select'
import { debounce } from '@/utils/util'
export interface DebounceSelectProps<ValueType = any>
extends Omit<SelectProps<ValueType | ValueType[]>, 'options' | 'children'> {
fetchOptions: (search: string) => Promise<IOption[]>
debounceTimeout?: number
// 值为空的时候过滤
filterEmpty?: boolean
// 首次加载组件搜索的值,传入则触发搜索
initialSearchKey?: string
}
type IOption = {
key?: string
label: React.ReactNode
value: string | number
}
function DebounceSelect<ValueType = any>({
fetchOptions,
debounceTimeout = 600,
filterEmpty = true,
initialSearchKey,
...props
}: DebounceSelectProps<ValueType>) {
const [fetching, setFetching] = useState(false)
const [options, setOptions] = useState<IOption[]>([])
const fetchRef = useRef(0)
const debounceFetcher = useMemo(() => {
const loadOptions = (value: string) => {
fetchRef.current += 1
const fetchId = fetchRef.current
setOptions([])
// if (filterEmpty && !value) {
// return
// }
setFetching(true)
fetchOptions(value).then((newOptions) => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return
}
setOptions(newOptions)
setFetching(false)
})
}
return debounce(loadOptions, debounceTimeout)
}, [fetchOptions, debounceTimeout, filterEmpty])
useEffect(() => {
if (initialSearchKey !== undefined) {
debounceFetcher(initialSearchKey)
}
}, [initialSearchKey])
return (
<Select
showSearch
filterOption={false}
onSearch={debounceFetcher}
notFoundContent={fetching ? <Spin size="small" /> : null}
{...props}
options={options}
/>
)
}
export default DebounceSelect
//index.tsx
const onNameSearch = (name: string) => {
return queryNamesList(name).then((res) => {
return res?.data?.map((item) => ({
label: item.name,
value: item.id,
}))
})
}
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '请选择名称' }]}
>
<DebounceSelect
placeholder="请选择名称,支持名称搜索"
fetchOptions={onNameSearch}
initialSearchKey={''}
/>
</Form.Item>