mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-29 17:07:22 +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>
|
</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
|
## 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.
|
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>
|
<script setup>
|
||||||
const ctr = ref(0)
|
const showMountain = ref(false)
|
||||||
const { data, refresh, pending } = await useAsyncData('/api/hello', () => $fetch(`/api/hello/${ctr.value}`), { watch: [ctr] })
|
|
||||||
|
const refreshing = ref(false)
|
||||||
|
const refreshAll = async () => {
|
||||||
|
refreshing.value = true
|
||||||
|
try {
|
||||||
|
await refreshNuxtData()
|
||||||
|
} finally {
|
||||||
|
refreshing.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtExampleLayout example="use-async-data" show-tips>
|
<NuxtExampleLayout example="use-async-data" show-tips>
|
||||||
<div>{{ data }}</div>
|
|
||||||
<div>
|
<div>
|
||||||
<NButton :disabled="pending" @click="refresh">
|
<div class="flex justify-center gap-2">
|
||||||
Refresh Data
|
<NButton @click="showMountain = !showMountain">
|
||||||
</NButton>
|
{{ showMountain ? 'Hide' : 'Show' }} Mountain
|
||||||
<NButton :disabled="pending" @click="ctr++">
|
</NButton>
|
||||||
+
|
<NButton :disabled="refreshing" @click="refreshAll">
|
||||||
</NButton>
|
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>
|
</div>
|
||||||
<template #tips>
|
<template #tips>
|
||||||
<div>
|
<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 defu from 'defu'
|
||||||
import { useNuxtApp } from './app'
|
import { useNuxtApp } from './app'
|
||||||
|
|
||||||
export { useLazyAsyncData } from './asyncData'
|
export { useLazyAsyncData, refreshNuxtData } from './asyncData'
|
||||||
export { useLazyFetch } from './fetch'
|
export { useLazyFetch } from './fetch'
|
||||||
export { useCookie } from './cookie'
|
export { useCookie } from './cookie'
|
||||||
export { useRequestHeaders } from './ssr'
|
export { useRequestHeaders } from './ssr'
|
||||||
|
@ -137,12 +137,15 @@ export function useAsyncData<
|
|||||||
asyncData.refresh()
|
asyncData.refresh()
|
||||||
}
|
}
|
||||||
if (options.watch) {
|
if (options.watch) {
|
||||||
const unwatch = watch(options.watch, () => {
|
watch(options.watch, () => asyncData.refresh())
|
||||||
asyncData.refresh()
|
}
|
||||||
})
|
const off = nuxt.hook('app:data:refresh', (keys) => {
|
||||||
if (instance) {
|
if (!keys || keys.includes(key)) {
|
||||||
onUnmounted(() => unwatch())
|
return asyncData.refresh()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
if (instance) {
|
||||||
|
onUnmounted(off)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +169,14 @@ export function useLazyAsyncData<
|
|||||||
return useAsyncData(key, handler, { ...options, lazy: true })
|
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[]) {
|
function pick (obj: Record<string, any>, keys: string[]) {
|
||||||
const newObj = {}
|
const newObj = {}
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export { defineNuxtComponent } from './component'
|
export { defineNuxtComponent } from './component'
|
||||||
export { useAsyncData, useLazyAsyncData } from './asyncData'
|
export { useAsyncData, useLazyAsyncData, refreshNuxtData } from './asyncData'
|
||||||
export type { AsyncDataOptions, AsyncData } from './asyncData'
|
export type { AsyncDataOptions, AsyncData } from './asyncData'
|
||||||
export { useHydration } from './hydrate'
|
export { useHydration } from './hydrate'
|
||||||
export { useState } from './state'
|
export { useState } from './state'
|
||||||
|
@ -23,6 +23,7 @@ export interface RuntimeNuxtHooks {
|
|||||||
'app:suspense:resolve': (Component?: VNode) => HookResult
|
'app:suspense:resolve': (Component?: VNode) => HookResult
|
||||||
'app:error': (err: any) => HookResult
|
'app:error': (err: any) => HookResult
|
||||||
'app:error:cleared': (options: { redirect?: string }) => HookResult
|
'app:error:cleared': (options: { redirect?: string }) => HookResult
|
||||||
|
'app:data:refresh': (keys?: string[]) => HookResult
|
||||||
'page:start': (Component?: VNode) => HookResult
|
'page:start': (Component?: VNode) => HookResult
|
||||||
'page:finish': (Component?: VNode) => HookResult
|
'page:finish': (Component?: VNode) => HookResult
|
||||||
'meta:register': (metaRenderers: Array<(nuxt: NuxtApp) => NuxtMeta | Promise<NuxtMeta>>) => HookResult
|
'meta:register': (metaRenderers: Array<(nuxt: NuxtApp) => NuxtMeta | Promise<NuxtMeta>>) => HookResult
|
||||||
|
@ -23,6 +23,7 @@ export const appPreset = defineUnimportPreset({
|
|||||||
imports: [
|
imports: [
|
||||||
'useAsyncData',
|
'useAsyncData',
|
||||||
'useLazyAsyncData',
|
'useLazyAsyncData',
|
||||||
|
'refreshNuxtData',
|
||||||
'defineNuxtComponent',
|
'defineNuxtComponent',
|
||||||
'useNuxtApp',
|
'useNuxtApp',
|
||||||
'defineNuxtPlugin',
|
'defineNuxtPlugin',
|
||||||
|
Loading…
Reference in New Issue
Block a user