mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 23:22:02 +00:00
feat: refreshNuxtData
function and app:data:refresh
hook (#3929)
Co-authored-by: Sébastien Chopin <seb@nuxtjs.com> Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
parent
e534ffe22f
commit
8dd77d7b6e
@ -168,6 +168,39 @@ watch(posts, (newPosts) => {
|
||||
</script>
|
||||
```
|
||||
|
||||
## `refreshNuxtData`
|
||||
|
||||
Invalidate the cache of `useAsyncData`, `useLazyAsyncData`, `useFetch` and `useLazyFetch` and trigger the refetch.
|
||||
|
||||
This method is useful if you want to refresh all the data fetching for a current page.
|
||||
|
||||
### Usage
|
||||
|
||||
```ts
|
||||
refreshNuxtData(keys?: string | string[])
|
||||
```
|
||||
|
||||
Available options:
|
||||
|
||||
* `keys`: Provides an array of keys that used in `useAsyncData` to refetch. When it's not specified, all `useAsyncData` and `useFetch` will be refetched.
|
||||
|
||||
### Example
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
{{ pending ? 'Loading' : count }}
|
||||
</div>
|
||||
<button @click="refresh">Refresh</button>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
|
||||
|
||||
const refresh = () => refreshNuxtData('count')
|
||||
</script>
|
||||
```
|
||||
|
||||
## Isomorphic fetch
|
||||
|
||||
When we call `fetch` in the browser, user headers like `cookie` will be directly sent to the API. But during server-side-rendering, since the `fetch` request takes place 'internally' within the server, it doesn't include the user's browser cookies, nor does it pass on cookies from the fetch response.
|
||||
|
@ -1,18 +1,35 @@
|
||||
<script setup>
|
||||
const ctr = ref(0)
|
||||
const { data, refresh, pending } = await useAsyncData('/api/hello', () => $fetch(`/api/hello/${ctr.value}`), { watch: [ctr] })
|
||||
const showMountain = ref(false)
|
||||
|
||||
const refreshing = ref(false)
|
||||
const refreshAll = async () => {
|
||||
refreshing.value = true
|
||||
try {
|
||||
await refreshNuxtData()
|
||||
} finally {
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtExampleLayout example="use-async-data" show-tips>
|
||||
<div>{{ data }}</div>
|
||||
<div>
|
||||
<NButton :disabled="pending" @click="refresh">
|
||||
Refresh Data
|
||||
</NButton>
|
||||
<NButton :disabled="pending" @click="ctr++">
|
||||
+
|
||||
</NButton>
|
||||
<div class="flex justify-center gap-2">
|
||||
<NButton @click="showMountain = !showMountain">
|
||||
{{ showMountain ? 'Hide' : 'Show' }} Mountain
|
||||
</NButton>
|
||||
<NButton :disabled="refreshing" @click="refreshAll">
|
||||
Refetch All Data
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center gap-2">
|
||||
<CounterExample />
|
||||
</div>
|
||||
<div class="flex justify-center gap-2">
|
||||
<MountainExample v-if="showMountain" />
|
||||
</div>
|
||||
</div>
|
||||
<template #tips>
|
||||
<div>
|
||||
|
19
examples/use-async-data/components/CounterExample.vue
Normal file
19
examples/use-async-data/components/CounterExample.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
const ctr = ref(0)
|
||||
const { data, pending, refresh } = await useAsyncData('/api/hello', () => $fetch(`/api/hello/${ctr.value}`), { watch: [ctr] })
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
{{ data }}
|
||||
<div class="flex justify-center gap-2">
|
||||
<NButton :disabled="pending" @click="ctr++">
|
||||
+
|
||||
</NButton>
|
||||
<NButton :disabled="pending" @click="refresh">
|
||||
⟳
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
9
examples/use-async-data/components/MountainExample.vue
Normal file
9
examples/use-async-data/components/MountainExample.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<script setup>
|
||||
const { data: mountain } = await useFetch(
|
||||
'https://api.nuxtjs.dev/mountains/mount-everest'
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<pre class="text-sm text-left overflow-auto">{{ mountain }}</pre>
|
||||
</template>
|
@ -8,7 +8,7 @@ import { sendRedirect } from 'h3'
|
||||
import defu from 'defu'
|
||||
import { useNuxtApp } from './app'
|
||||
|
||||
export { useLazyAsyncData } from './asyncData'
|
||||
export { useLazyAsyncData, refreshNuxtData } from './asyncData'
|
||||
export { useLazyFetch } from './fetch'
|
||||
export { useCookie } from './cookie'
|
||||
export { useRequestHeaders } from './ssr'
|
||||
|
@ -137,12 +137,15 @@ export function useAsyncData<
|
||||
asyncData.refresh()
|
||||
}
|
||||
if (options.watch) {
|
||||
const unwatch = watch(options.watch, () => {
|
||||
asyncData.refresh()
|
||||
})
|
||||
if (instance) {
|
||||
onUnmounted(() => unwatch())
|
||||
watch(options.watch, () => asyncData.refresh())
|
||||
}
|
||||
const off = nuxt.hook('app:data:refresh', (keys) => {
|
||||
if (!keys || keys.includes(key)) {
|
||||
return asyncData.refresh()
|
||||
}
|
||||
})
|
||||
if (instance) {
|
||||
onUnmounted(off)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,6 +169,14 @@ export function useLazyAsyncData<
|
||||
return useAsyncData(key, handler, { ...options, lazy: true })
|
||||
}
|
||||
|
||||
export function refreshNuxtData (keys?: string | string[]): Promise<void> {
|
||||
if (process.server) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
const _keys = keys ? Array.isArray(keys) ? keys : [keys] : undefined
|
||||
return useNuxtApp().callHook('app:data:refresh', _keys)
|
||||
}
|
||||
|
||||
function pick (obj: Record<string, any>, keys: string[]) {
|
||||
const newObj = {}
|
||||
for (const key of keys) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
export { defineNuxtComponent } from './component'
|
||||
export { useAsyncData, useLazyAsyncData } from './asyncData'
|
||||
export { useAsyncData, useLazyAsyncData, refreshNuxtData } from './asyncData'
|
||||
export type { AsyncDataOptions, AsyncData } from './asyncData'
|
||||
export { useHydration } from './hydrate'
|
||||
export { useState } from './state'
|
||||
|
@ -23,6 +23,7 @@ export interface RuntimeNuxtHooks {
|
||||
'app:suspense:resolve': (Component?: VNode) => HookResult
|
||||
'app:error': (err: any) => HookResult
|
||||
'app:error:cleared': (options: { redirect?: string }) => HookResult
|
||||
'app:data:refresh': (keys?: string[]) => HookResult
|
||||
'page:start': (Component?: VNode) => HookResult
|
||||
'page:finish': (Component?: VNode) => HookResult
|
||||
'meta:register': (metaRenderers: Array<(nuxt: NuxtApp) => NuxtMeta | Promise<NuxtMeta>>) => HookResult
|
||||
|
@ -23,6 +23,7 @@ export const appPreset = defineUnimportPreset({
|
||||
imports: [
|
||||
'useAsyncData',
|
||||
'useLazyAsyncData',
|
||||
'refreshNuxtData',
|
||||
'defineNuxtComponent',
|
||||
'useNuxtApp',
|
||||
'defineNuxtPlugin',
|
||||
|
Loading…
Reference in New Issue
Block a user