feat(nuxt): support deep: false for data composables (#23600)

This commit is contained in:
Sacha Stafyniak 2023-10-16 14:56:23 +02:00 committed by GitHub
parent 6b3d0163b6
commit 830f4f4aa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 20 additions and 2 deletions

View File

@ -26,6 +26,7 @@ type AsyncDataOptions<DataT> = {
server?: boolean server?: boolean
lazy?: boolean lazy?: boolean
immediate?: boolean immediate?: boolean
deep?: boolean
default?: () => DataT | Ref<DataT> | null default?: () => DataT | Ref<DataT> | null
transform?: (input: DataT) => DataT transform?: (input: DataT) => DataT
pick?: string[] pick?: string[]
@ -60,6 +61,7 @@ type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
* _transform_: a function that can be used to alter `handler` function result after resolving * _transform_: a function that can be used to alter `handler` function result after resolving
* _pick_: only pick specified keys in this array from the `handler` function result * _pick_: only pick specified keys in this array from the `handler` function result
* _watch_: watch reactive sources to auto-refresh * _watch_: watch reactive sources to auto-refresh
* _deep_: return data in a deep ref object (it is `true` by default). It can be set to `false` to return data in a shallow ref object, which can improve performance if your data does not need to be deeply reactive.
Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience. Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience.

View File

@ -26,6 +26,7 @@ type UseFetchOptions<DataT> = {
server?: boolean server?: boolean
lazy?: boolean lazy?: boolean
immediate?: boolean immediate?: boolean
deep?: boolean
default?: () => DataT default?: () => DataT
transform?: (input: DataT) => DataT transform?: (input: DataT) => DataT
pick?: string[] pick?: string[]
@ -72,6 +73,7 @@ All fetch options can be given a `computed` or `ref` value. These will be watche
* `transform`: a function that can be used to alter `handler` function result after resolving * `transform`: a function that can be used to alter `handler` function result after resolving
* `pick`: only pick specified keys in this array from the `handler` function result * `pick`: only pick specified keys in this array from the `handler` function result
* `watch`: watch an array of reactive sources and auto-refresh the fetch result when they change. Fetch options and URL are watched by default. You can completely ignore reactive sources by using `watch: false`. Together with `immediate: false`, this allows for a fully-manual `useFetch`. * `watch`: watch an array of reactive sources and auto-refresh the fetch result when they change. Fetch options and URL are watched by default. You can completely ignore reactive sources by using `watch: false`. Together with `immediate: false`, this allows for a fully-manual `useFetch`.
* `deep`: return data in a deep ref object (it is `true` by default). It can be set to `false` to return data in a shallow ref object, which can improve performance if your data does not need to be deeply reactive.
::alert{type=warning} ::alert{type=warning}
If you provide a function or ref as the `url` parameter, or if you provide functions as arguments to the `options` parameter, then the [`useFetch`](/docs/api/composables/use-fetch) call will not match other [`useFetch`](/docs/api/composables/use-fetch) calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in `options`. If you provide a function or ref as the `url` parameter, or if you provide functions as arguments to the `options` parameter, then the [`useFetch`](/docs/api/composables/use-fetch) call will not match other [`useFetch`](/docs/api/composables/use-fetch) calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in `options`.

View File

@ -24,3 +24,12 @@ Because the data inside [`useState`](/docs/api/composables/use-state) will be se
::ReadMore{link="/docs/getting-started/state-management"} ::ReadMore{link="/docs/getting-started/state-management"}
:: ::
## Using `shallowRef`
If you don't need your state to be deeply reactive, you can combine `useState` with [`shallowRef`](https://vuejs.org/api/reactivity-advanced.html#shallowref). This can improve performance when your state contains large objects and arrays.
```ts
const state = useState('my-shallow-state', () => shallowRef({ deep: 'not reactive' }))
// isShallow(state) === true
```

View File

@ -1,4 +1,4 @@
import { getCurrentInstance, onBeforeMount, onServerPrefetch, onUnmounted, ref, toRef, unref, watch } from 'vue' import { getCurrentInstance, onBeforeMount, onServerPrefetch, onUnmounted, ref, shallowRef, toRef, unref, watch } from 'vue'
import type { Ref, WatchSource } from 'vue' import type { Ref, WatchSource } from 'vue'
import type { NuxtApp } from '../nuxt' import type { NuxtApp } from '../nuxt'
import { useNuxtApp } from '../nuxt' import { useNuxtApp } from '../nuxt'
@ -44,6 +44,7 @@ export interface AsyncDataOptions<
pick?: PickKeys pick?: PickKeys
watch?: MultiWatchSources watch?: MultiWatchSources
immediate?: boolean immediate?: boolean
deep?: boolean
} }
export interface AsyncDataExecuteOptions { export interface AsyncDataExecuteOptions {
@ -148,8 +149,10 @@ export function useAsyncData<
if (!nuxt._asyncData[key] || !options.immediate) { if (!nuxt._asyncData[key] || !options.immediate) {
nuxt.payload._errors[key] ??= null nuxt.payload._errors[key] ??= null
const _ref = options.deep !== true ? shallowRef : ref
nuxt._asyncData[key] = { nuxt._asyncData[key] = {
data: ref(getCachedData() ?? options.default!()), data: _ref(getCachedData() ?? options.default!()),
pending: ref(!hasCachedData()), pending: ref(!hasCachedData()),
error: toRef(nuxt.payload._errors, key), error: toRef(nuxt.payload._errors, key),
status: ref('idle') status: ref('idle')

View File

@ -107,6 +107,7 @@ export function useFetch<
pick, pick,
watch, watch,
immediate, immediate,
deep,
...fetchOptions ...fetchOptions
} = opts } = opts
@ -122,6 +123,7 @@ export function useFetch<
transform, transform,
pick, pick,
immediate, immediate,
deep,
watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])] watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])]
} }