Advertisement
metalni

infinite scroll\

Feb 28th, 2023
925
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { Form, Select } from 'antd'
  2. import { Rule } from 'antd/lib/form'
  3. import axios from 'axios'
  4. import { debounce } from 'lodash'
  5. import { FC, useEffect, useState, CSSProperties, useMemo } from 'react'
  6.  
  7. const { Option } = Select
  8.  
  9. interface IAsyncSelectProps {
  10.   url: string
  11.   name: string
  12.   label: string
  13.   initialValue: number | string | undefined
  14.   rules?: Rule[] | undefined
  15.   showSearch: boolean
  16.   allowClear: boolean
  17.   style: CSSProperties | undefined
  18.   placeholder: string
  19.   onChange?: (value: any) => void
  20.   size: 'large' | 'middle' | 'small'
  21.   dataMap: (element: any) => JSX.Element
  22.   searchKey: string
  23. }
  24.  
  25. export const AsyncSelect: FC<IAsyncSelectProps> = ({
  26.   url,
  27.   name,
  28.   label,
  29.   initialValue,
  30.   rules,
  31.   showSearch,
  32.   allowClear,
  33.   style,
  34.   placeholder,
  35.   size,
  36.   dataMap,
  37.   searchKey,
  38.   onChange,
  39. }) => {
  40.   const [page, setPage] = useState(1)
  41.   const [maxPage, setMaxPage] = useState<number>(99)
  42.   const [dataFromFetch, setDataFromFetch] = useState<any[]>([])
  43.   const [searchData, setSearchData] = useState<any[]>([])
  44.   const [loading, setLoading] = useState(false)
  45.  
  46.   useEffect(() => {
  47.     fetchData()
  48.   }, [])
  49.  
  50.   useEffect(() => {
  51.     return () => {
  52.       handleDebouncedSearch.cancel()
  53.     }
  54.   })
  55.  
  56.   const fetchSearchData = async (query: string) => {
  57.     if (!query || query === '') {
  58.       refetchData()
  59.       return
  60.     }
  61.     setLoading(true)
  62.     const {
  63.       data: { data },
  64.     } = await axios.get(`${url}?filters[${searchKey}][$containsi]=${query}`)
  65.  
  66.     setLoading(false)
  67.     setSearchData(data)
  68.     resetData()
  69.   }
  70.  
  71.   const fetchInitialData = async () => {
  72.     const {
  73.       data: { data },
  74.     } = await axios.get(`${url}/${initialValue}`)
  75.     return data
  76.   }
  77.  
  78.   const fetchData = async () => {
  79.     setLoading(true)
  80.     const {
  81.       data: { data, meta },
  82.     } = await axios.get(
  83.       `${url}?pagination[page]=${page}&pagination[pageSize]=10`,
  84.     )
  85.  
  86.     if (dataFromFetch.length === 0) {
  87.       const initialData = await fetchInitialData()
  88.       if (!data.some((item: any) => item.id === initialValue))
  89.         data.unshift(initialData)
  90.       setDataFromFetch(data)
  91.     }
  92.  
  93.     if (maxPage === 99) {
  94.       setMaxPage(meta?.pagination?.pageCount)
  95.     }
  96.     setPage(page  1)
  97.  
  98.     setLoading(false)
  99.     return data.filter((item: any) => item.id !== initialValue)
  100.   }
  101.  
  102.   const onScroll = async (event: any) => {
  103.     const { target } = event
  104.  
  105.     if (
  106.       target.scrollTop  target.offsetHeight === target.scrollHeight &&
  107.       page <= maxPage &&
  108.       searchData.length === 0
  109.     ) {
  110.       const newData = await fetchData()
  111.       target.scrollTo(0, target.scrollHeight)
  112.       setDataFromFetch(dataFromFetch.concat(newData))
  113.     }
  114.   }
  115.  
  116.   const handleDebouncedSearch = useMemo(() => {
  117.     return debounce(fetchSearchData, 300)
  118.   }, [])
  119.  
  120.   const resetData = () => {
  121.     setDataFromFetch([])
  122.     setPage(1)
  123.   }
  124.  
  125.   const refetchData = () => {
  126.     resetData()
  127.     setSearchData([])
  128.  
  129.     fetchData()
  130.   }
  131.  
  132.   return (
  133.     <Form.Item
  134.       name={name}
  135.       label={label}
  136.       initialValue={initialValue}
  137.       rules={rules}
  138.     >
  139.       <Select
  140.         showSearch={showSearch}
  141.         allowClear={allowClear}
  142.         style={style}
  143.         onPopupScroll={onScroll}
  144.         onSearch={handleDebouncedSearch}
  145.         filterOption={false}
  146.         placeholder={placeholder}
  147.         size={size}
  148.         onClear={refetchData}
  149.         onChange={onChange}
  150.       >
  151.         {searchData.length === 0
  152.           ? dataFromFetch.map((item) => dataMap(item))
  153.           : searchData.map((item) => dataMap(item))}
  154.         {loading && <Option>Loading...</Option>}
  155.       </Select>
  156.     </Form.Item>
  157.   )
  158. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement