import { Select, Spin } from 'antd'; import debounce from 'lodash/debounce'; import difference from 'lodash/difference'; import { useEffect, useState } from 'react'; /** * 懒加载 Select ,适用于数据超大的下拉框 * @param {Select 官方属性} props */ const LazySelect = (props) => { const { value, onChange, query, pageSize } = props; // 清除 porps 中 query,避免控制台警告 const selectProps = { ...props, query: undefined }; const [selected, setSelected] = useState(value); const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [current, setCurrent] = useState(1); const [total, setTotal] = useState(0); const [searchText] = useState(''); const getSelectedArray = (obj) => { let selectedValues = obj; // 如果是单选,将值封装为数组 if (obj && obj instanceof Array === false) { selectedValues = [obj]; } return selectedValues; }; // 添加 300 毫秒防抖 const handleQuery = debounce(async (param) => { setLoading(true); const resp = await query(param); const resData = resp.data; let options = resData?.data?.map((p: any) => { return { ...p, label: p.productName, value: p.productName, key: p.id, }; }); // 搜索服务端异步加载 // const handleSearch = (filter) => { // setSearchText(filter); // handleQuery({ // filter, // selectedValues: getSelectedArray(selected), // pageSize, // current // }); // }; //第一个商品默认为要新增的商品 // if (searchValue?.trim() !== "") { // options.unshift({ productName: searchValue, type: "add", label: searchValue, value: searchValue }) // } // return options; setTotal(resData.total); setData(data.concat(options)); setLoading(false); }, 300); // 组件初始化时加载一次数据 useEffect(() => { handleQuery({ filter: '', selectedValues: getSelectedArray(value), }); }, []); // 外部注入的 value 变化后,如果 value 在 data 中不存在,则加载数据 useEffect(() => { setSelected(value); const dataKeys = data.map((item) => item.value); const diff = difference(getSelectedArray(value), dataKeys); if (diff && diff.length > 0) { handleQuery({ filter: '', selectedValues: getSelectedArray(value), }); } }, [value]); const keywordChange = (newWord: string) => { setData([]); setTotal(0); setCurrent(1); handleSearch(newWord); }; const handleChange = (newValue, option) => { setSelected(newValue); if (onChange) { // 将值通过 onChange 传递到外部 onChange(newValue, option); } }; const scrollEnd = (e) => { e.persist(); const { target } = e; // 滚动 触底 看接口是否还有剩余的值没传过来 if (target.scrollTop + target.offsetHeight === target.scrollHeight) { if (current * pageSize < total) { setCurrent(current + 1); handleSearch(searchText); } } }; return ( <Select {...selectProps} value={selected} loading={loading} onSearch={keywordChange} onChange={handleChange} onPopupScroll={scrollEnd} filterOption={false} options={data} showSearch showArrow notFoundContent={loading ? <Spin size="small" /> : null} > {/* {data.map(d => ( <Option key={d.value} title={d.label}> {d.label} </Option> ))} */} </Select> ); }; export default LazySelect;