React-query: How to use useInfiniteQuery with custom props

Created on 1 Apr 2020  路  10Comments  路  Source: tannerlinsley/react-query

Let's picture situation where we have filters with infinite scroll data view.

So I have have code like this:

// api
const queryPosts = async (props = {}) => {
  const { sort, page } = props
  const res = await axios.get(`/posts?sort=${sort}&page=${page}`)
  return {
    items: res.data,
    page,
  }
}

// Posts
const [sort, setSort] = React.useState('views')
const payload = useInfiniteQuery(
  ['infinite-posts', { sort, page: 1 }],
  queryPosts,
  {
    getFetchMore: lastGroup => {
      const { items, group } = lastGroup
      if (items.length) {
        return { page: page + 1, sort }
      }
      return false
    }
  }
)

At first it triggers correct, but when I call () => fetchMore() sort is disappeared, and page remains as initial.

Maybe I'm doing something wrong?

Most helpful comment

The issue here is that you are not mapping up your query key to your query function's arguments properly. Each item in the query key is passed to the query function, including infinite-posts in your case. The next issue is that you're not accounting that the result from getFetchMore is passed as an optional parameter to your query function, which is why on the first request, you must provide a default value.

async function queryPosts (key, sort, page = 1) {
  // key === 'infinite-posts'
  // sort will always be there from the query-key
  // page information won't be there on the first request
  // which is why is has a defualt value of 1, but it will be
  // there on subsequent requests
  const res = await axios.get(`/posts?sort=${sort}&page=${page}`)

  return {
    items: res.data,
    page,
  }
}

const queryInfo = useInfiniteQuery(['infinite-posts', sort], queryPosts, {
  getFetchMore: ({ items, page }) => {
    if (items.length) {
      return page + 1 // This will be sent as the LAST parameter to your query function
    }

    return false
  },
})

All 10 comments

Unfortunately I have the same issue, is not clear from the docs how to use it :(

The issue here is that you are not mapping up your query key to your query function's arguments properly. Each item in the query key is passed to the query function, including infinite-posts in your case. The next issue is that you're not accounting that the result from getFetchMore is passed as an optional parameter to your query function, which is why on the first request, you must provide a default value.

async function queryPosts (key, sort, page = 1) {
  // key === 'infinite-posts'
  // sort will always be there from the query-key
  // page information won't be there on the first request
  // which is why is has a defualt value of 1, but it will be
  // there on subsequent requests
  const res = await axios.get(`/posts?sort=${sort}&page=${page}`)

  return {
    items: res.data,
    page,
  }
}

const queryInfo = useInfiniteQuery(['infinite-posts', sort], queryPosts, {
  getFetchMore: ({ items, page }) => {
    if (items.length) {
      return page + 1 // This will be sent as the LAST parameter to your query function
    }

    return false
  },
})

@tannerlinsley what is the proper way to update the sort in your example? are the queryPost automatically updated when sort changes?

Yep! You can update it however you'd like (via state, props, etc). Since it's part of the query key, it will automatically trigger a new refetch when it changes.

@tannerlinsley thx a lot for the help. I loved the lib, for me is the missing abstraction for the hooks + fetching.

:) You're welcome! Thanks for using it! You should consider writing a blog post on that thought. It sounds like a great prompt: "React Query: The missing abstraction for hooks and data fetching"

@tannerlinsley thanks it works.

One more question:
Is there a possibility to change in queryPosts (key, sort, page = 1) second parameter via fetchMore?
As I can see fetchMore changing only third parameter

You would have to do that override in the query function itself and use an optional override sort if it's there from the fetchMore

Hello, I think this could be better documented. I also had trouble using useInfiniteQuery with an additional parameter until I found this issue.

I absolute agree with @ralrom 's ideas

Was this page helpful?
0 / 5 - 0 ratings