Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement useQuery pagination #820

Closed
flybayer opened this issue Apr 25, 2020 · 4 comments · Fixed by blitz-js/blitz#278
Closed

Implement useQuery pagination #820

flybayer opened this issue Apr 25, 2020 · 4 comments · Fixed by blitz-js/blitz#278

Comments

@flybayer
Copy link
Member

flybayer commented Apr 25, 2020

React-query provides a separate hook for pagination (usePaginatedQuery), but we want to support pagination with the same useQuery by accepting the paginated: true option.

Summary:

  • If {paginated: true} is passed as third option to useQuery, then Blitz will use usePaginatedQuery from react-query instead of the plain useQuery from react-query.
  • Everything should be properly typed. I think the main thing that's currently missing is the type for latestData
  • Add this to the example store app

Example usage:

For this example, the getProducts query result would have this shape:

{
  products: [],
  hasMore: false
}
import { useQuery } from 'blitz'
import getProducts from '/app/products/queries/getProducts'

function Products(props) {
  const [page, setPage] = React.useState(0)

  const [
    data, // whatever is returned from getProducts query, in this case an object
    {
      latestData,
      isFetching,
    }
  ] = useQuery(
    getProducts, 
    {where: {storeId: props.storeId}, first: 100, skip: 0 * (page * 100)},
    {paginated: true}
  )

  return (
    <div>
      // `data` will either resolve to the latest page's data
      // or if fetching a new page, the last successful page's data
      <div>
        {data.products.map(product => (
          <p key={product.id}>{product.name}</p>
        ))}
      </div>
      <span>Current Page: {page + 1}</span>
      <button onClick={() => setPage(old => Math.max(old - 1, 0))} disabled={page === 0}>
        Previous Page
      </button>{' '}
      <button
        onClick={() =>
          // Here, we use `latestData` so the Next Page
          // button isn't relying on potentially old data
          setPage(old => (!latestData || !latestData.hasMore ? old : old + 1))
        }
        disabled={!latestData || !latestData.hasMore}
      >
        Next Page
      </button>
      {// Since the last page's data potentially sticks around between page requests,
      // we can use `isFetching` to show a background loading
      // indicator since our `status === 'loading'` state won't be triggered
      isFetching ? <span> Loading...</span> : null}{' '}
    </div>
  )
}

Note: It's possible I've overlooked something critical in the above code, so is something doesn't seem right, it might not be right!

@eliashelleborn
Copy link
Contributor

Hey, would love to have a go at this :)

@flybayer
Copy link
Member Author

@eliasjohansson ok awesome!

@eliashelleborn
Copy link
Contributor

@flybayer In your example above you are using hasMore. I cannot seem to find where this is coming from.. Did you just copy the react-query example? Im guessing that property is specific to the API they are using? In our case latestData will just be an Array of the return type.

@flybayer
Copy link
Member Author

@eliasjohansson ah yes, the example was incorrect. I just updated it along with the return data from the getProducts query. (hasMore is part of the data returned from the query)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants