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

[legacy-framework] Add useQuery pagination & add pagination to store example #278

Merged
merged 10 commits into from
Apr 27, 2020
1 change: 0 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,4 @@ Closes: ??

<!-- Before/after screenshots, etc. -->


<!-- IMPORTANT: Make sure to check the "Allow edits from maintainers" box below this window -->
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
47 changes: 47 additions & 0 deletions examples/store/app/products/pages/products/paginated.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {Suspense, useState} from 'react'
import {Link, BlitzPage, useQuery} from 'blitz'
import getProducts from 'app/products/queries/getProducts'

const ITEMS_PER_PAGE = 3

const Products = () => {
const [page, setPage] = useState(0)
const [products] = useQuery(
getProducts,
{
skip: ITEMS_PER_PAGE * page,
first: ITEMS_PER_PAGE,
},
{paginated: true},
)

return (
<div>
{products.map((product) => (
<p key={product.id}>
<Link href="/products/[handle]" as={`/products/${product.handle}`}>
<a>{product.name}</a>
</Link>
</p>
))}
<button disabled={page === 0} onClick={() => setPage(page - 1)}>
Previous
</button>
<button disabled={products.length !== ITEMS_PER_PAGE} onClick={() => setPage(page + 1)}>
Next
</button>
</div>
)
}

const Page: BlitzPage = function () {
return (
<div>
<h1>Products - Paginated</h1>
<Suspense fallback={<div>Loading...</div>}>
<Products />
</Suspense>
</div>
)
}
export default Page
55 changes: 44 additions & 11 deletions packages/core/src/useQuery.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,56 @@
import {useQuery as useReactQuery} from 'react-query'
import {
useQuery as useReactQuery,
usePaginatedQuery as usePaginatedReactQuery,
PaginatedQueryResult,
QueryResult,
QueryOptions,
} from 'react-query'
import {PromiseReturnType, InferUnaryParam} from './types'

type QueryFn = (...args: any) => Promise<any>

// interface QueryFn {
// (...args: any): Promise<any>
// cacheKey: string
// }
interface Options<T> extends QueryOptions<T> {
paginated?: boolean
}

/**
* Get useQuery result without "data"
*/
type RestQueryResult<T extends QueryFn> = Omit<QueryResult<PromiseReturnType<T>>, 'data'>

/**
* Get usePaginatedQuery result without "resolvedData"
*/
type RestPaginatedQueryResult<T extends QueryFn> = Omit<
PaginatedQueryResult<PromiseReturnType<T>>,
'resolvedData'
>

export function useQuery<T extends QueryFn>(
/**
* Get "rest" object return value based on paginated option
*/
type RestReturnType<T extends QueryFn, O extends Options<T>> = O['paginated'] extends true
? RestPaginatedQueryResult<T>
: RestQueryResult<T>

export function useQuery<T extends QueryFn, O extends Options<T>>(
queryFn: T,
params?: InferUnaryParam<T>,
options: any = {},
): [PromiseReturnType<T>, Record<any, any>] {
const {data, ...rest} = useReactQuery([(queryFn as any).cacheKey, params], (_, params) => queryFn(params), {
options?: O,
): [PromiseReturnType<T>, RestReturnType<T, O>] {
const queryKey: [string, any] = [(queryFn as any).cacheKey, params]
const queryFunction = (_: string, params: {}) => queryFn(params)
const queryOptions = {
suspense: true,
retry: process.env.NODE_ENV === 'production' ? 3 : false,
...options,
})
}

if (options?.paginated) {
const {resolvedData, ...rest} = usePaginatedReactQuery(queryKey, queryFunction, queryOptions)
return [resolvedData as PromiseReturnType<T>, rest as RestReturnType<T, O>]
}

return [data as PromiseReturnType<T>, rest]
const {data, ...rest} = useReactQuery(queryKey, queryFunction, queryOptions)
return [data as PromiseReturnType<T>, rest as RestReturnType<T, O>]
}