DEV Community

inno
inno

Posted on

React antd 滚动加载List组件逻辑

  • 如何判断何时加载 根据antd List中的loadMore属性 当loadMore按钮在可视区域时,加载数据,反之不加载数据

Image description

  • 如何判断loadMore按钮是否在可见区域内 使用ahooks的useInViewport判断

Image description

  • 无限滚动加载数据(只有滚动加载时才需要请求数据放在同一个数组中) 增加滚动加载的标识
  const newItems = asl.infinite ? asl.items.concat(items) : items
Enter fullscreen mode Exit fullscreen mode

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
  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
Enter fullscreen mode Exit fullscreen mode
  • package request conponent
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
Enter fullscreen mode Exit fullscreen mode
  • use it
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>
Enter fullscreen mode Exit fullscreen mode
  • achievement

Image description

Top comments (0)