最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - useSWRInfinite - getKey function always gets pageIndex as 1 - Stack Overflow

programmeradmin1浏览0评论

I am using the SWRInfinite example as defined here () and here (/examples/infinite-loading).

My code is as below...

import React from 'react'
import {useSelector} from 'react-redux'
import useSWRInfinite from 'swr/infinite'
import {Button, Grid, Typography} from '@material-ui/core'
import getNearbyShops from '../../../lib/nearshop-apis.js'
import ShopThumbnail from './shop-thumbnail.js'
import Spacer from '../../../ponents/utils/spacer'

const PAGE_SIZE=10

export default function Nearbyshops({category, categoryName}) {

  const getKey = (pageIndex, previousPageData, category) => {
    console.log("getKey::pageIndex", pageIndex)
    // reached the end?
    if (previousPageData && !previousPageData.data) return null

    return [`/api/nearbyshops/${pageIndex+1}`, pageIndex+1, PAGE_SIZE, category]
  }


  const {data, error, size, setSize} = useSWRInfinite ( getKey, getNearbyShops)

  const shops = data ? [].concat(...data) : [];
  const isLoadingInitialData = !data && !error;
  const isLoadingMore =
          isLoadingInitialData || (size > 0 && data && typeof data[size-1] === 'undefined')
  //const isEmpty = data[0].length === 0;
  const isEmpty = data?.[0]?.length === 0;
  const isReachingEnd =
        isEmpty || (data && data[data.length-1].length < PAGE_SIZE);
  //const isRefreshing = isValidating && data && data.length===size;

  const currentShop = useSelector(state => state.main.currentShop);
  const bg = currentShop.sColor
  const fg = currentShop.pColor
  const title = categoryName?`NEAR BY ${categoryName} SHOPS`:'NEAR BY SHOPS'

  return (
    <Grid>
      <Typography variant='body2' style={{fontWeight:'bold',color:fg,marginTop:"12px",boxShadow: "0px 2px 2px rgba(0, 0, 0, 0.25)"}}>{title}</Typography>
      <Spacer space={2}/>
      {
        shops.map((shop, index) => {
          return <ShopThumbnail key={shop.id} shop={shop} showDistance={true} />
        })
      }
      <Button
          style={{backgroundColor:fg, color:bg}}
          disabled={isLoadingMore || isReachingEnd}
          onClick={() => setSize(size+1)}
          variant='contained'
          fullWidth
      >
        {
          isLoadingMore
            ? "Loading..."
            : isReachingEnd
            ? "No more shops"
            : "Show More"
        }
      </Button>
    </Grid>
  )
}

It loads the 1st page correctly. However, when I click the 'Show More' button where I do onClick={() => setSize(size+1)}, the getKey function doesn't get the next index value, and hence always gets 1.

What am I doing wrong here?

I am using the SWRInfinite example as defined here (https://github./vercel/swr/discussions/732) and here (https://swr.vercel.app/examples/infinite-loading).

My code is as below...

import React from 'react'
import {useSelector} from 'react-redux'
import useSWRInfinite from 'swr/infinite'
import {Button, Grid, Typography} from '@material-ui/core'
import getNearbyShops from '../../../lib/nearshop-apis.js'
import ShopThumbnail from './shop-thumbnail.js'
import Spacer from '../../../ponents/utils/spacer'

const PAGE_SIZE=10

export default function Nearbyshops({category, categoryName}) {

  const getKey = (pageIndex, previousPageData, category) => {
    console.log("getKey::pageIndex", pageIndex)
    // reached the end?
    if (previousPageData && !previousPageData.data) return null

    return [`/api/nearbyshops/${pageIndex+1}`, pageIndex+1, PAGE_SIZE, category]
  }


  const {data, error, size, setSize} = useSWRInfinite ( getKey, getNearbyShops)

  const shops = data ? [].concat(...data) : [];
  const isLoadingInitialData = !data && !error;
  const isLoadingMore =
          isLoadingInitialData || (size > 0 && data && typeof data[size-1] === 'undefined')
  //const isEmpty = data[0].length === 0;
  const isEmpty = data?.[0]?.length === 0;
  const isReachingEnd =
        isEmpty || (data && data[data.length-1].length < PAGE_SIZE);
  //const isRefreshing = isValidating && data && data.length===size;

  const currentShop = useSelector(state => state.main.currentShop);
  const bg = currentShop.sColor
  const fg = currentShop.pColor
  const title = categoryName?`NEAR BY ${categoryName} SHOPS`:'NEAR BY SHOPS'

  return (
    <Grid>
      <Typography variant='body2' style={{fontWeight:'bold',color:fg,marginTop:"12px",boxShadow: "0px 2px 2px rgba(0, 0, 0, 0.25)"}}>{title}</Typography>
      <Spacer space={2}/>
      {
        shops.map((shop, index) => {
          return <ShopThumbnail key={shop.id} shop={shop} showDistance={true} />
        })
      }
      <Button
          style={{backgroundColor:fg, color:bg}}
          disabled={isLoadingMore || isReachingEnd}
          onClick={() => setSize(size+1)}
          variant='contained'
          fullWidth
      >
        {
          isLoadingMore
            ? "Loading..."
            : isReachingEnd
            ? "No more shops"
            : "Show More"
        }
      </Button>
    </Grid>
  )
}

It loads the 1st page correctly. However, when I click the 'Show More' button where I do onClick={() => setSize(size+1)}, the getKey function doesn't get the next index value, and hence always gets 1.

What am I doing wrong here?

Share Improve this question asked Oct 20, 2021 at 13:27 Mopparthy RavindranathMopparthy Ravindranath 3,3288 gold badges48 silver badges88 bronze badges 2
  • 1 Are you sure this condition if (previousPageData && !previousPageData.data) return null is correct for your API? It sounds to me like SWR assumes it has reached the end after page 1. – Thomas Ebert Commented Nov 17, 2021 at 14:00
  • 1 Yes, it was some logical error on my part. I corrected it and it works fine. – Mopparthy Ravindranath Commented Dec 28, 2021 at 3:04
Add a ment  | 

3 Answers 3

Reset to default 7

For people finding this on google, make sure that the if (previousPageData && !previousPageData.data) return null line is properly checking YOUR API's response data. In my case i had to change it to if (previousPageData && !previousPageData.data.length) return null; // reached the end

The example from https://swr.vercel.app/docs/pagination#example-1-index-based-paginated-api

has the line

if (previousPageData && !previousPageData.length) return null

whereas you have

if (previousPageData && !previousPageData.data) return null

Is this the change you made to fix it?

Considering the above answers, the response in your API probably has a pageable list usually in an array, so you should use that name exactly.

For instance, if you have in the response { data:[...] } then use !previousPageData.data if it is { products:[...]} then use !previousPageData.products.

That's how useSWRInfinite hook checks for changes. I hope this helps it worked for me.

发布评论

评论列表(0)

  1. 暂无评论