React antd 滚动加载List组件逻辑
Published: 2023-01-30 10:18:21

- 如何判断何时加载
根据[antd](https://ant.design/components/list-cn#list) List中的loadMore属性
当loadMore按钮在可视区域时，加载数据，反之不加载数据

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3edckddsgl9wkqu075eq.png)


- 如何判断loadMore按钮是否在可见区域内  
使用ahooks的[useInViewport](https://ahooks.js.org/zh-CN/hooks/use-in-viewport)判断

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6u7xnvb6bo4ec09x1dlx.png)
- 无限滚动加载数据(只有滚动加载时才需要请求数据放在同一个数组中) 增加滚动加载的标识 

```javascript
  const newItems = asl.infinite ? asl.items.concat(items) : items
```
1.编辑参数（page:1,pageSize:10,infinite:false）
2.删除参数（page:1,pageSize:10,infinite:false） 
3.查询参数（page:1,pageSize:10,infinite:false）
4.无限滚动加载参数（page:page+1,pageSize:10,infinite:true）
只需在每次调用加载数据时page加一即可
###so now i will show you how to achieve it
- package AutoLoadMoreList component
we need some basic conditions to judge

```javascript
  import { useDebounceEffect, useInViewport } from "ahooks";
import { Button, List, Spin } from "antd"
import { useRef } from "react";

interface Props<T> {
    height?: number
    dataSource: T[]
    renderItem: (item: T) => React.ReactNode
    loading:boolean //是否正在请求数据true：正在请求，false:请求完成
    loadMore:()=>void  //滚动加载数据
    next:string|null  //是否还有数据

}
function AutoLoadMoreList<T>({ height, dataSource, renderItem,loading,loadMore,next }: Props<T>) {
    const loadMoreButtonRef = useRef(null)
    const [inViewport] = useInViewport(loadMoreButtonRef)
    useDebounceEffect(()=>{
        if (inViewport) {  //如果在可视区域加载数据
            if (next) {
                loadMore() 
            }
           
        }
    },[inViewport],{ wait: 1000})
    const loadMoreButton = <div
        ref={loadMoreButtonRef}
        style={{
            textAlign: 'center',
            marginTop: 12,
            height: 32,
            lineHeight: '32px',
        }}
    >
        <Button>loading more</Button>
    </div>
    return <div style={{ height: height }}>
        <Spin spinning={loading}>
        <List
            className="demo-loadmore-list"
            itemLayout="horizontal"
            loadMore={loadMoreButton}
            dataSource={dataSource}
            renderItem={renderItem}
        />
        </Spin>
    </div>
}
export default AutoLoadMoreList
```
- package request conponent
```javascript
import request from '@/packages/request';
import { useDebounceEffect } from 'ahooks';
import { message } from 'antd';

import { useState} from 'react'
interface responseType<T>{
    ok:boolean
    count:number|null
    next:string|null
    results:T|null
    error:string

}

interface GetType{url:string
    params:Record<string,unknown>}
const Get=async<T>({url,params}:GetType):Promise<responseType<T>>=>{
    try {
        const result=  await request(url, { method: 'GET', params: params }) as any

        return {
            ok:true,
            count:result.data.count as number,
            next:result.data.next,
            results:result.data.results as T,
            error:'' 
        }
    } catch (error) {
        return {
            ok:false,
            count:null,
            next:null,
            results:null,
            error: 'fail'
        } 
    }
 


}
type QueryType={
    page:number
    pageSize:number
    [key:string]:unknown
}
function useAsl<T>(url:string) {
 const [infinite,setInfinite] =useState<boolean>(false)
 const [query,setQuery]= useState<QueryType>({page:1,pageSize:10})
 const [loading,setLoading]= useState<boolean>(false)
 const [dataSource, setDataSource] = useState<T[]>([])
 const [next, setNext] = useState<string|null>(null)

 useDebounceEffect(()=>{
    const getList=async()=>{
        setLoading(true)
        const {ok,results,error,next}=await Get<T[]>({url,params:query})
     
        if (ok&&results) {
          const dateArr= infinite ?dataSource.concat(results):results
          setDataSource(dateArr)
          setNext(next) 
     

        }else{
            message.error(error)
        }
        setLoading(false)
    }
    getList().then()
  
 },[url,query],{wait:100}) 

 
 const loadMore=()=>{
    setInfinite(true)
    setQuery(query=>({...query,page:query.page+1}))
 }


 return {dataSource,loading,loadMore,next}
}
export default useAsl
```
- use it
```javascript
const {dataSource,loading,loadMore,next}= useAsl<NotificationType>('/notice_message/message/manage')
  <div className={Styles.tabTwo}>
          <AutoLoadMoreList<NotificationType>
          dataSource={dataSource}
          loading={loading}
          loadMore={loadMore}
          next={next}
          renderItem={(item)=><div key={item.uuid}>{item.content}</div>}
          />
          </div>
```
- achievement

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hszjpdf62j3hf2dsag6.png)