fix(nuxt3): allow customising page keys (#2859)

This commit is contained in:
Daniel Roe 2022-01-24 10:35:28 +00:00 committed by GitHub
parent 3125c72e09
commit 83a959a67b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 4 deletions

View File

@ -134,6 +134,29 @@ To display the `child.vue` component, you have to insert the `<NuxtNestedPage
</template> </template>
``` ```
### Child route keys
If you want more control over when the `<NuxtNestedPage>` component is re-rendered (for example, for transitions), you can either pass a string or function via the `childKey` prop, or you can define a `key` value via `definePageMeta`:
```html{}[pages/parent.vue]
<template>
<div>
<h1>I am the parent view</h1>
<NuxtNestedPage :child-key="someKey" />
</div>
</template>
```
Or alternatively:
```html{}[pages/child.vue]
<script setup>
definePageMeta({
key: route => route.fullPath
})
</script>
```
## Page Metadata ## Page Metadata
You might want to define metadata for each route in your app. You can do this using the `definePageMeta` macro, which will work both in `<script>` and in `<script setup>`: You might want to define metadata for each route in your app. You can do this using the `definePageMeta` macro, which will work both in `<script>` and in `<script setup>`:
@ -175,6 +198,10 @@ definePageMeta({
Of course, you are welcome to define metadata for your own use throughout your app. But some metadata defined with `definePageMeta` has a particular purpose: Of course, you are welcome to define metadata for your own use throughout your app. But some metadata defined with `definePageMeta` has a particular purpose:
#### `key`
[See above](#child-route-keys).
#### `layout` #### `layout`
You can define the layout used to render the route. This can be either false (to disable any layout), a string or a ref/computed, if you want to make it reactive in some way. [More about layouts](/docs/directory-structure/layouts). You can define the layout used to render the route. This can be either false (to disable any layout), a string or a ref/computed, if you want to make it reactive in some way. [More about layouts](/docs/directory-structure/layouts).

View File

@ -20,6 +20,12 @@ const route = useRoute()
<NuxtLink to="/parent/b" class="n-link-base"> <NuxtLink to="/parent/b" class="n-link-base">
Parent (b) Parent (b)
</NuxtLink> </NuxtLink>
<button class="n-link-base" @click="$router.push(`/parent/reload-${(Math.random() * 100).toFixed()}`)">
Keyed child
</button>
<button class="n-link-base" @click="$router.push(`/parent/static-${(Math.random() * 100).toFixed()}`)">
Non-keyed child
</button>
</nav> </nav>
</template> </template>

View File

@ -0,0 +1,13 @@
<template>
<div>
Child reloaded: {{ reloads }}
</div>
</template>
<script setup>
const reloads = useState('reload', () => 0)
onMounted(() => { reloads.value++ })
definePageMeta({
key: route => route.path
})
</script>

View File

@ -0,0 +1,10 @@
<template>
<div>
Child reloaded: {{ reloads }}
</div>
</template>
<script setup>
const reloads = useState('static', () => 0)
onMounted(() => { reloads.value++ })
</script>

View File

@ -14,6 +14,7 @@ export interface PageMeta {
[key: string]: any [key: string]: any
transition?: false | TransitionProps transition?: false | TransitionProps
layout?: false | string | Ref<false | string> | ComputedRef<false | string> layout?: false | string | Ref<false | string> | ComputedRef<false | string>
key?: string | ((route: RouteLocationNormalizedLoaded) => string)
// TODO: https://github.com/vuejs/vue-next/issues/3652 // TODO: https://github.com/vuejs/vue-next/issues/3652
// keepalive?: false | KeepAliveProps // keepalive?: false | KeepAliveProps
} }

View File

@ -1,11 +1,31 @@
<template> <template>
<RouterView v-slot="{ Component }"> <RouterView v-slot="{ Component }">
<component :is="Component" :key="$route.path" /> <component :is="Component" :key="key" />
</RouterView> </RouterView>
</template> </template>
<script> <script lang="ts">
import type { RouteLocationNormalizedLoaded } from 'vue-router'
import { useRoute } from 'vue-router'
import { computed } from 'vue'
export default { export default {
name: 'NuxtNestedPage' name: 'NuxtNestedPage',
props: {
childKey: {
type: [Function, String] as unknown as () => string | ((route: RouteLocationNormalizedLoaded) => string),
default: null
}
},
setup (props) {
const route = useRoute()
const key = computed(() => {
const source = props.childKey ?? route.meta.key
return typeof source === 'function' ? source(route) : source
})
return {
key
}
}
} }
</script> </script>

View File

@ -3,7 +3,7 @@
<NuxtLayout v-if="Component" :name="layout || route.meta.layout"> <NuxtLayout v-if="Component" :name="layout || route.meta.layout">
<NuxtTransition :options="route.meta.transition ?? { name: 'page', mode: 'out-in' }"> <NuxtTransition :options="route.meta.transition ?? { name: 'page', mode: 'out-in' }">
<Suspense @pending="() => onSuspensePending(Component)" @resolve="() => onSuspenseResolved(Component)"> <Suspense @pending="() => onSuspensePending(Component)" @resolve="() => onSuspenseResolved(Component)">
<component :is="Component" :key="route.path" /> <component :is="Component" />
</Suspense> </Suspense>
</NuxtTransition> </NuxtTransition>
</NuxtLayout> </NuxtLayout>