The useFind
Method
Learn how to perform automatic queries with built-in pagination support.
The service.useFind
function is a Vue Composition API utility that takes the work out of retrieving lists of records from the store or API server.
Overview of Features
The service.useFind
utility is a workflow-driven utility. Here's an overview of its features:
- Intelligent Fall-Through Caching - Like SWR, but way smarter.
- Live Queries - For server data, reactive records. For client-side data, reactive lists and records. No need to manually refresh data.
- Client-Side Pagination - Built in, sharing the same logic with
usePagination
. - Server-Side Pagination - Also built in and made super easy.
- Infinite Pagination Support - Bind to
allData
and tell it when to load more data. - Declarative Workflow Support - Compose computed params and let query as they change.
- Imperative Workflow Support - Pass reactive params for imperative control.
Usage
In Feathers-Pinia 3.0, the useFind
utility is only available as a service method.
Recommended
You can call useFind
directly from the Model. avoiding the need to manually pass the store
in the params, as shown here:
interface Props {
userId: string | number
}
const props = defineProps<Props>()
const { api } = useFeathers()
const params = computed(() => {
return { query: { userId: props.userId } }
})
// client-side pagination with manual fetch
const { data, prev, next } = api.service('messages').useFind(params)
await api.service('messages').find({ query: { $limit: 100 } }) // retrieve data for the current query
await next() // show the next page of results
await prev() // show the previous page of results
// server-side pagination with auto fetch
const { data, prev, next } = api.service('messages').useFind(params, { paginateOn: 'server' })
await next() // retrieve the next page of results
await prev() // retrieve the previous page of results
API
service.useFind(params)
params
can be areactive
aref
or acomputed
object of the following structure:query
{Object} required a Feathers query object.clones
{Boolean} returns result as clones. See Querying Datatemps
{Boolean} includes temp records in the results. See Querying Dataqid
{string} an identifier for this query. Allows pagination data to be tracked separately.
options
paginateOn
{string} can be'client'
,'server'
, or'hybrid'
Default is'client'
.- when set to
'client'
, you need to manually make API queries usingservice.find()
, then you can paginate on that data without making additional requests. - when set to
'server'
, the internalfindInStore
getter will return only the results that match the current query in thepagination
object for this store. Settingpaginate: 'server'
gives up live lists and gives all control to the API server, which means you have to refetch in order for results to change. Refetching currently happens whenever acreated
,updated
, orremoved
event is provided. This will potentially be refined in the future. - when set to
'hybrid'
, you get server-side pagination with live lists. This will likely become the default in the future.
- when set to
pagination
{Object} an object containing two refs:$limit
and$skip
. This allows you to synchronize the internally-controlled pagination with UI-bound$limit
and$skip
properties.immediate
{boolean = true} whenpaginateOn: 'server'
is set, by default it will make an initial request. Setimmediate: false
to prevent the initial request.watch
{boolean = false} enable this to automatically query whenreactive
orref
params are changed. This does not apply tocomputed
params, since they are automatically watched.
Returned Object
The useFind
function is actually a factory function that returns an instance of the Find
class. So when you call useFind
you get back an object with the following properties:
Params & Config
isSsr
{Computed boolean} will be true ifisSsr
was passed into theuseService
options for this service store. Useful for awaint therequest
during SSR.qid
{Ref string} the query identifier. Causes this query's pagination data to be stored under its ownqid
instore.pagination
.
Data
data
{Ref Array} the array of results.allData
{Ref Array} all results for the matching query or server-retrieved data. WithpaginateOn: 'server'
, will return the correct results, even with custom query params that the store does not understand.total
{Computed number} One of two things: For client-side results, the total number of records in the store that match the query. ForpaginateOn: 'server'
results, the total number of records on the server that match the query.
Query Tracking
currentQuery
{Computed Object} an object containing the following:qid
{string} the query identifierids
{number[]} the ids in this page of dataitems
{Record[]} the items in this page of datatotal
{number} the total number of items matching this queryqueriedAt
{number} the timestamp when this page of data was retrieved. Useful when used withqueryWhen
to prevent repeated queries during a period of time.queryState
{Object} a pagination object from the store
latestQuery
{Computed Object} an object containing the following:pageId
{string} stable stringified page paramspageParams
{Object} the page paramsqueriedAt
{number} timestamp when this page of records was received from the server.query
{Object} the query params, including $limit and $skip.queryId
{string} stable-stringified query paramsqueryParams
{Object} the query params, excluding $limit and $skip.total
{number} the total number of records matching the query.
previousQuery
{Computed Object} an object with the same format aslatestQuery
.
Data Retrieval & Watching
find
{Function} the same asstore.find
.request
{Ref Promise} the promise for the current request.requestCount
{Computed number} the number of requests sent by thisFind
instance.queryWhen
{Function} pass a function that returns a boolean intoqueryWhen
and that function will be run before retrieving data. If it returns false, the query will not happen.findInStore
{Function} the same asstore.findInStore
.
Request State
isPending
{Computed boolean} returns true if the currentrequest
is pending.haveBeenRequested
{Computed boolean} returns true if any request has been sent by thisFind
instance. Never resets for the life of the instance.haveLoaded
{Computed boolean} essentially the same purpose, but opposite ofisPending
. Returns true once the request finishes.error
{Computed error} will contain any error. The error will be cleared when a new request is made or when manually callingclearError
.clearError
{Function} call this function to clear theerror
.
Pagination Utils
limit
{Ref number} the pagination$limit
. Updating this value will change the internal pagination and the returneddata
.skip
{Ref number} the pagination$skip
. Updating this value will change the internal pagination and the returneddata
.pageCount
{Computed number} the number of pages for the current query params.currentPage
{Ref number} the current page number. Can be set to change to that page, or usetoPage(pageNumber)
.canPrev
{Computed boolean} returns true if there is a previous page.canNext
{Computed boolean} returns true if there is a next page.next
{Function} moves to the next page of data.prev
{Function} moves to the previous page of data.toStart
{Function} moves to the first page of data.toEnd
{Function} moves to the last page of data.toPage(pageNumber)
{Function}
Examples
Let's look at the two most-common use cases: client-side pagination and server-side pagination.
Client Paging with Live Lists
If you want live-updating lists, use client-side pagination. You set the page size in the initial query. Then you can use the find
utility to request multiple pages of data. The example below sets $limit
to 10
, which determines the page size. It then retrieves 25 pages of data ($limit: 250
) in a separate query.
const { api } = useFeathers()
const params = computed(() => {
return query: { $limit: 10, $skip: 0 }
})
// Set page size with $limit in the initial query
const { data, next, prev, find } = api.service('posts').useFind(params)
// fetch multiple pages of data
await api.service('posts').find({ query: { $limit: 250 } })
// move to the next page
await next()
// move to the previous page
await prev()
Server Paging, Auto Fetch
Another common use case is server-side pagination (gives the server full control and disables live-updating lists). Enable it by passing paginateOn: 'server'
in the options. You can also pull out isPending
to show a status indicator when a request is pending. That's it!
Note
When you enable paginateOn: 'server'
, all control is given to the server, which disables live list updates. For live lists, use client-side pagination, as shown in the previous example.
const { api } = useFeathers()
// pagination attributes can go inside params if you don't need external control,
// like for Vuetify or other components.
const pagination = { $limit: ref(10), $skip: ref(0) }
const params = computed(() => {
return query: {}
})
const { data, next, prev, isPending } = api.service('posts').useFind(params, {
pagination,
paginateOn: 'server'
})
// move to the next page
await next()
// move to the previous page
await prev()