vfetcher
Version:
Vue composables for fetching data, based on unjs/ofetch
386 lines (282 loc) • 11.2 kB
Markdown
# vfetcher
English | [简体中文](/README-zh.md)
Vue composables for fetching data, based on [unjs/ofetch](https://github.com/unjs/ofetch).
```sh
$ pnpm i vfetcher
```
## Features
- Carefully designed API: Intentionally mimicking the [nuxt/useFetch](https://nuxt.com.cn/docs/api/composables/use-fetch) API to maintain consistency as much as possible and reduce migration burden.
- More features: Throttling/debouncing/polling/pagination out of the box... and more features to come!
## Usage
> Visit [examples](/examples/src/) to see the config examples, visit [test](/test/) to see the usage examples.
### Re-export ofetch
`vfetcher` re-export all exports of `ofetch` so you can directly use ofetch:
```ts
import { $fetch } from 'vfetcher/ofetch'
```
### Basic Examples
The first parameter of `useAsyncData` is a callback function, and the second parameter is its configuration object. By default, the callback is automatically called during initialization:
```ts
import { useAsyncData } from 'vfetcher'
const { data } = useAsyncData(() => $fetch('/return-ok'))
watchEffect(() => {
console.log(data.value) // Ref
// -> null
// -> 'ok'
})
```
Use the `immediate: false` option to prevent the request from being sent automatically during initialization:
```ts
const { data, execute, refresh } = useAsyncData(() => $fetch('return-ok'), {
immediate: false
})
watchEffect(() => {
console.log(data.value)
})
// -> null
// await refresh() // as alias of execute
await execute()
// -> 'ok'
```
The `watch` option accepts the same values as the first parameter of Vue's `watch`. When these reactive variables change, a request will be automatically sent:
```ts
const dep = ref('foo')
useAsyncData(() => $fetch('ok'), {
watch: [dep]
})
// request to => 'ok'
dep.value = 'bar'
// request to => 'ok'
```
The `ready` option accepts a reactive boolean value or a function that returns a boolean. A request is only sent when the result is true; if the result is false, the `execute` is terminated immediately, and no request is sent. This is useful when using dependent requests with specific conditions:
```ts
const ready = ref(false)
const { execute } = useAsyncData(() => $fetch('ok'), {
immediate: false,
ready
})
await execute()
// the promise will be resolved immediately and no request will be sent
ready.value = true
await execute()
// request to => 'ok'
```
The `status` return value of `useAsyncData` indicates the current state. By monitoring the `status`, you can implement callbacks in different situations. The `status` is initially `idle`, indicating an idle state; it changes to `pending` before the request is sent, indicating a waiting response. Upon successful request, it changes to `success`, indicating success, or to `error` if the request fails:
```ts
const { status } = useAsyncData(() => $fetch('ok'))
// Equivalent to `onSuccess` hook:
watch(status, (v) => {
if (v !== 'success')
return
onSuccess()
})
```
通过 `transform` 选项对返回值进行预处理:
```ts
const { data } = useAsyncData(() => $fetch('post', {
method: 'post',
body: {
number: {
one: 1
}
}
}), {
transform: (res: { number: { one: 1 } }) => res.number.one
})
// request to => 'post'
// response `{ number: { one: 1 } }`
data.value === 1 // true
```
Use the `pollingInterval` option to perform polling requests:
```ts
useAsyncData(() => $fetch('ok'), {
pollingInterval: 2000 // 2 seconds
})
// request to => 'ok'
// wait 2 seconds...
// request to => 'ok'
const { execute } = useAsyncData(() => $fetch('ok'), {
pollingInterval: 2000, // 2 seconds
immediate: false
})
// ...
// Will not poll until `execute` is called for the first time.
await execute() // request to => 'ok'
// wait 2 seconds...
// request to => 'ok'
```
Use the `debounceInterval` option to apply debouncing:
```ts
const { execute } = useAsyncData(() => $fetch('ok'), {
debounceInterval: 2000 // 2 seconds
})
await execute()
// request to => 'ok'
execute()
execute()
// after about 2 seconds
// request to => 'ok'
```
Use the `throttleInterval` option to apply throttling:
```ts
const { execute } = useAsyncData(() => $fetch('ok'), {
throttleInterval: 2000 // 2 seconds
})
await execute()
// request to => 'ok'
execute()
execute()
// after about 2 seconds
await execute()
// request to => 'ok'
```
### Customize the default options
You could customize `useAsyncData` to configure your favorite default options:
```ts
import { useAsyncData as $ } from 'vfetcher'
export const useAsyncData = $.create({
immediate: false
})
const { execute } = useAsyncData(() => $fetch('ok'))
// ...
await execute()
```
The new `useAsyncData` will extend the default options of the previous one:
```ts
import { useAsyncData as $1 } from 'vfetcher'
const $2 = $1.create({
debounceInternal: 150
})
const useAsyncData = $2.create({
immediate: false
})
useAsyncData(() => $fetch('ok'))
// Equal to:
// `useAsyncData(() => $fetch('ok'), { debounceInternal: 150, immediate: false })`
```
### Returns
Except for `execute/refresh`, all other variables are wrapped by ref:
- `data`: The result returned by the asynchronous request, defaulting to `null`, with the result being the return value of `ofetch`.
- `pending`: A boolean value indicating whether the data is still being fetched.
- `error`: The error object if the data fetch fails, otherwise `null`.
- `status`: A string representing the state of the data request (`idle`, `pending`, `success`, `error`).
- `execute/refresh`: A **function** used to manually trigger the request.
### Options
- `immediate`: A boolean value indicating whether to make a request during initialization. Defaults to true.
- `watch`: Watches a set of reactive sources, similar to the first parameter type of the Vue `watch` method. When the reactive sources change, a new request will be made. By default, it watches the request URL and request parameters (detailed below), but you can manually set it to false to disable this feature.
- `transform`: A function that can be used to alter handler function result after resolving.
- `default`: A function which returns the initial value of `data` above.
- `pollingInterval`: Can be a reactive value. Pass a `number`, in milliseconds, to indicate the interval time for polling. By default, polling is not enabled.
- `debounceInterval`: Can be a reactive value. Pass a `number`, in milliseconds, to indicate the debounce delay time. By default, debounce is not enabled.
- `throttleInterval`: Can be a reactive value. Pass a `number`, in milliseconds, to indicate the throttle wait time. By default, throttling is not enabled.
## useFetch
`useFetch` is almost a combination of `useAsyncData` and `ofetch`:
- The first parameter is basically the same as the first parameter of `ofetch`.
- The second parameter accepts all configuration options of both `useAsyncData` and `ofetch`.
- The return value is the same as that of `useAsyncData`.
Thanks to `ofetch`, the data will be automatically converted to the appropriate type:
```ts
const { data: d1 } = useFetch('/return-ok')
watchEffect(() => {
console.log(d1.value)
// -> null
// -> 'ok'
})
const { data: d2 } = useFetch('/return-json')
watchEffect(() => {
console.log(d2.value)
// -> null
// -> { one: 1 }
})
```
Request parameters such as the request path, headers, query, body, etc., can be passed in as reactive values, which will automatically trigger requests when they change:
```ts
const url = ref('return-ok')
const query = ref({ one: '1' })
const { data } = useFetch(url, { query })
watchEffect(() => {
console.log(data.value)
})
// -> null
// -> 'ok'
url.value = 'return-query'
// -> { one: '1' }
query.value = { two: '2' }
// -> { two: '2' }
```
Similar to `useAsyncData`, you can configure your preferred default parameters, as mentioned above:
```js
import { useFetch as $ } from 'vfetcher'
export const useFetch = $.create({
// ...
})
```
`useFetch` shares the same return values and options as `useAsyncData`. It also accepts all options from `ofetch`, and by default, it monitors the following parameters from `ofetch`:
- `URL`: The request path URL.
- `method`: The request method type.
- `query`: Query parameters.
- `params`: Just an alias for `query`.
- `body`: The request body.
- `headers`: Request headers.
- `baseURL`: The base URL for the request.
> ... For other general options of `ofetch`, please refer to the [ofetch official documentation](https://github.com/unjs/ofetch).
## Pagination
Use `usePagination` function to handle pagination.
`import { usePagination } from 'vfetcher'`
### Basic usage
`usePagination` is a wrapper around `useFetch`:
- The first parameter is the same as in `usePagination`.
- The second parameter is a configuration object, containing all the configurations of `useFetch`.
- The return value includes all the return values of `useFetch`.
You can directly use the configuration options of `useFetch`.
```ts
usePagination('ok', {
immediate: false
})
```
It automatically merge the params of pagination to query:
```ts
usePagination('getByPage')
// request to => `/getByPage?current=1&pageSize=10`
```
Compared to `useFetch`, some new return values have been added, which are also responsive:
```ts
const { pageCurrent } = usePagination('getByPage')
// request to => `/getByPage?current=1&pageSize=10`
pageCurrent.value = 2
// request to => `/getByPage?current=2&pageSize=10`
```
Get pageSize and total data counts by `lodash - get` , or you can configure the param key manually:
```ts
const { data, total } = usePagination('getByPage', {
totalKey: 'res.total'
})
watchEffect(() => {
console.log(data.value)
if (data.value)
console.log(total.value)
})
// -> null
// -> { res: { total:10, data:[ /* ... */]} }
// -> 10
```
Same as useFetch, you can also configure the default params you like. See above for details:
```js
import { usePagination as $ } from 'vfetcher'
export const usePagination = $.create({
// ...
})
```
### New Return Values and Options
`usePagination` includes all the options and return values of `useFetch`. In addition, it also has some options and return values specific to itself.
All new return values are reactive variables:
- `pageCurrent`: Indicates the current page number (number).
- `pageSize`: Indicates the number of items per page (number).
- `total`: Indicates the total number of items (read-only number).
- `pageTotal`: Indicates the total number of pages (read-only number).
New Options
- `pageCurrentKey`: Indicates the key name for the current page number, used in the query. Default is `'current'`.
- `pageSizeKey`: Indicates the key name for the number of items per page, used in the query. Default is `'pageSize'`.
- `defaultPageSize`: Indicates the default number of items per page (number), useful when `immediate: true`. Default is `10`.
- `totalKey`: The key name for fetching the total number of items, obtained from the returned data using `lodash - get`. Default is `'total'`.
- `pageTotalKey`: The key name for fetching the total number of pages, obtained from the returned data using `lodash - get`. Default is `'totalPage'`.