React 滚动加载--ahooks--useInfiniteScroll

本文介绍了如何在React项目中利用ahooks库的useInfiniteScroll实现滚动加载功能。useInfiniteScroll封装了无限滚动逻辑,通过传入异步服务函数和服务选项来获取和合并数据。内容包括基本用法、参数解析、API说明及示例代码,重点解释了data、loading、loadingMore和noMore等关键属性的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在此之前:您可以移步去官网ahooks了解详情

useInfiniteScroll基本介绍

useInfiniteScroll 封装了常见的无限滚动逻辑。

const { data, loading, loadingMore, loadMore } = useInfiniteScroll(service);

useInfiniteScroll 的第一个参数 service 是一个异步函数,对这个函数的入参和出参有如下约定:

  1. service 返回的数据必须包含 list 数组,类型为 { list: any[], ...rest }
  2. service 的入参为整合后的最新 data

假如第一次请求返回数据为 { list: [1, 2, 3], nextId: 4 }, 第二次返回的数据为 { list: [4, 5, 6], nextId: 7 }, 则我们会自动合并 list,整合后的的 data 为 { list: [1, 2, 3, 4, 5, 6], nextId: 7 }

注:这里官方说了对于返回的字段是list,才会帮你进行合并,所以可以跟后端的同学商量返回的数组数据用list做属性名,或者你也可以拿到后端的数据自己生成list属性名。

参数--(参照官网)

Result

参数说明类型
dataservice 返回的数据,其中的 list 属性为聚合后数据TData | undefined
loading是否正在进行首次请求boolean
loadingMore是否正在进行更多数据请求boolean
noMore是否没有更多数据了,配置 options.isNoMore 后生效boolean
loadMore加载更多数据,会自动捕获异常,通过 options.onError 处理() => void
loadMoreAsync加载更多数据,与 loadMore 行为一致,但返回的是 Promise,需要自行处理异常() => Promise<TData>
reload加载第一页数据,会自动捕获异常,通过 options.onError 处理() => void
reloadAsync加载第一页数据,与 reload 行为一致,但返回的是 Promise,需要自行处理异常() => Promise<TData>
mutate直接修改 data(data?: TData) => void
cancel忽略当前 Promise 的响应() => void

 options

参数说明类型默认值
target父级容器,如果存在,则在滚动到底部时,自动触发 loadMore。需要配合 isNoMore 使用,以便知道什么时候到最后一页了。() => Element | Element | MutableRefObject<Element>-
isNoMore是否有最后一页的判断逻辑,入参为当前聚合后的 data(data?: TData) => boolean-
threshold下拉自动加载,距离底部距离阈值number100
reloadDeps变化后,会自动触发 reloadany[]-
manual
  • 默认 false。 即在初始化时自动执行 service。
  • 如果设置为 true,则需要手动调用 reload 或 reloadAsync 触发执行。
booleanfalse
onBeforeservice 执行前触发() => void-
onSuccessservice resolve 时触发(data: TData) => void-
onErrorservice reject 时触发(e: Error) => void-
onFinallyservice 执行完成时触发(data?: TData, e?: Error) => void-

API使用

:这里只是介绍基本应用,如果是想了解详情请移步官网https://ahooks.gitee.io/zh-CN/hooks/use-infinite-scroll

const { data, loading, loadingMore, noMore } = useInfiniteScroll(callback,{

        target: ref,

        isNoMore: (d) => d?.total <= d?.list?.length,

});

data:返回的是处理后的数据(合并后);

loading:在请求时的状态,请求中为true,请求结束为false,注意,这里只会在初始化改变。

loadingMore:这个跟loading的不同之处在于每次在加载更多的时候的loading状态,每一次的改变都会及时改变true/false状态

noMore:是否还有更多的数据可加载,配合options中的isNoMore一起使用

target:就是要绑定的父容器

isNoMore:true为已经没有数据加载,false还有数据可加载

const transList = async (page: Page) => {
    let result = await getRewards(page)
    //这里的result数据是data的命名,所以转一下list --> list: result?.data?.data,
    let data = {
      list: result?.data?.data,
      total: result?.data?.total,
      ...result,
    }
    return data
  }
  const { data, loading, loadingMore, noMore } = useInfiniteScroll(
    (d) => {
      // 无需写其他依赖,只需要在这里改变page就OK
      const page = d ? Math.ceil(d?.data?.data.length / PAGE_SIZE) + 1 : 1
      return transList({ page, pagesize: PAGE_SIZE })
    },
    {
      // ref --> 直接useRef(),之后把这个use之后的ref绑定到父容器上
      target: ref,
      // d 就是transList函数返回的data
      isNoMore: (d) => d?.total <= d?.list?.length,
    },
  )

1.这里传入的函数(transList)手动转成带list属性名的返回数据,hook监测到才会进行合并

2.d就是返回的合并后的数据

3.isNoMore: (d) => d?.total <= d?.list?.length,这里来做判断是否还要继续进行请求

详细代码

import React, { useState, useRef, useEffect, useMemo } from 'react'
import styles from './styles'
import { Box, Stack, Typography, CircularProgress } from '@mui/material'
import Image from 'next/image'
import { getRewards } from '@/api/profile'

import { useInfiniteScroll } from 'ahooks'
import moment from 'moment'
import NoData from '../NoData'

type Page = {
  page: number
  pagesize: number
}
const Reward: React.FC = () => {
  const PAGE_SIZE = 3
  const ref = useRef<HTMLDivElement>(null)

  const transList = async (page: Page) => {
    let result = await getRewards(page)
    let params = {
      list: result?.data?.data,
      total: result?.data?.total,
      ...result,
    }
    return params
  }
  const { data, loading, loadingMore, noMore } = useInfiniteScroll(
    (d) => {
      const page = d ? Math.ceil(d?.data?.data.length / PAGE_SIZE) + 1 : 1
      return transList({ page, pagesize: PAGE_SIZE })
    },
    {
      target: ref,
      isNoMore: (d) => d?.total <= d?.list?.length,
    },
  )
  // data返回的数据,会是合并后
  const rewardList = data?.list || []
  return (
//渲染data中的数据
    <Box sx={[rewardList?.length && styles.rewardBox]} ref={ref}>
      {rewardList &&
        !!rewardList?.length &&
        rewardList.map((reword: any, index: number) => (
          <Stack key={index} direction="row" spacing={1} sx={{ marginBottom: 60 }}>
           ......
          </Stack>
        ))}
// loading,loadingMore会在请求的时候发生改变,可以做loading效果,noMore在没有数据时会为true,其他情况多都是false,可以用来做nodata效果
      <Box sx={{ height: 200 }}>
        {loading || loadingMore ? <CircularProgress color="secondary" /> : noMore && <NoData />}
      </Box>
    </Box>
  )
}

export default Reward

以上就是滚动加载最基本的使用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值