useNuxtApp
useNuxtApp
是一个内置的组合式函数,提供了一种访问 Nuxt 共享运行时上下文的方式,也称为 Nuxt 上下文,它在客户端和服务器端都可用(但在 Nitro 路由中不可用)。 它可以帮助您访问 Vue 应用实例、运行时钩子、运行时配置变量和内部状态,例如 ssrContext
和 payload
。
<script setup lang="ts">
const nuxtApp = useNuxtApp()
</script>
如果运行时上下文在您的作用域中不可用,则调用 useNuxtApp
时会抛出异常。 您可以使用 tryUseNuxtApp
来代替不需要 nuxtApp
的组合式函数,或者只是检查上下文是否可用而不会引发异常。
方法
provide (name, value)
nuxtApp
是一个运行时上下文,您可以使用 Nuxt 插件来扩展它。 使用 provide
函数创建 Nuxt 插件,以使值和辅助方法在您的 Nuxt 应用程序的所有组合式函数和组件中都可用。
provide
函数接受 name
和 value
参数。
const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', (name) => `Hello ${name}!`)
// Prints "Hello name!"
console.log(nuxtApp.$hello('name'))
正如您在上面的示例中看到的,$hello
已成为 nuxtApp
上下文的新的自定义部分,并且它在所有可以访问 nuxtApp
的地方都可用。
hook(name, cb)
nuxtApp
中可用的钩子允许您自定义 Nuxt 应用程序的运行时方面。 您可以在 Vue.js 组合式函数和 Nuxt 插件中使用运行时钩子来钩入渲染生命周期。
hook
函数对于通过在特定点钩入渲染生命周期来添加自定义逻辑非常有用。 hook
函数主要在创建 Nuxt 插件时使用。
请参阅 运行时钩子,了解 Nuxt 调用的可用运行时钩子。
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
/* your code goes here */
})
nuxtApp.hook('vue:error', (..._args) => {
console.log('vue:error')
// if (import.meta.client) {
// console.log(..._args)
// }
})
})
callHook(name, ...args)
当使用任何现有钩子调用时,callHook
返回一个 promise。
await nuxtApp.callHook('my-plugin:init')
属性
useNuxtApp()
公开以下属性,您可以使用这些属性来扩展和自定义您的应用程序并共享状态、数据和变量。
vueApp
vueApp
是全局 Vue.js 应用程序实例,您可以通过 nuxtApp
访问它。
一些有用的方法
component()
- 如果同时传递名称字符串和组件定义,则注册全局组件;如果仅传递名称,则检索已注册的组件。directive()
- 如果同时传递名称字符串和指令定义,则注册全局自定义指令;如果仅传递名称,则检索已注册的指令(示例)。use()
- 安装 Vue.js 插件 (示例)。
ssrContext
ssrContext
在服务器端渲染期间生成,并且仅在服务器端可用。
Nuxt 通过 ssrContext
公开以下属性
url
(string) - 当前请求 url。event
(unjs/h3 请求事件) - 访问当前路由的请求和响应。payload
(object) - NuxtApp payload 对象。
payload
payload
将来自服务器端的数据和状态变量暴露给客户端。 以下键在从服务器端传递后将在客户端上可用
serverRendered
(boolean) - 指示响应是否为服务器端渲染。data
(object) - 当您使用useFetch
或useAsyncData
从 API 端点获取数据时,可以从payload.data
访问结果 payload。 此数据被缓存,并帮助您防止在多次发出相同的请求时获取相同的数据。<script setup lang="ts"> const { data } = await useAsyncData('count', () => $fetch('/api/count')) </script>
在上面的示例中使用useAsyncData
获取count
的值后,如果您访问payload.data
,您将看到{ count: 1 }
记录在那里。
当从ssrcontext
访问相同的payload.data
时,您也可以在服务器端访问相同的值。state
(object) - 当您在 Nuxt 中使用useState
组合式函数来设置共享状态时,可以通过payload.state.[您的状态名称]
访问此状态数据。plugins/my-plugin.tsexport const useColor = () => useState<string>('color', () => 'pink') export default defineNuxtPlugin((nuxtApp) => { if (import.meta.server) { const color = useColor() } })
也可以使用更高级的类型,例如ref
、reactive
、shallowRef
、shallowReactive
和NuxtError
。
自从 Nuxt v3.4 以来,可以为您自己的 Nuxt 不支持的类型定义 reducer/reviver。
在下面的示例中,我们使用 payload 插件为 Luxon DateTime 类定义了一个 reducer(或序列化器)和一个 reviver(或反序列化器)。plugins/date-time-payload.ts/** * This kind of plugin runs very early in the Nuxt lifecycle, before we revive the payload. * You will not have access to the router or other Nuxt-injected properties. * * Note that the "DateTime" string is the type identifier and must * be the same on both the reducer and the reviver. */ export default definePayloadPlugin((nuxtApp) => { definePayloadReducer('DateTime', (value) => { return value instanceof DateTime && value.toJSON() }) definePayloadReviver('DateTime', (value) => { return DateTime.fromISO(value) }) })
isHydrating
使用 nuxtApp.isHydrating
(boolean) 检查 Nuxt 应用程序是否正在客户端进行 hydration。
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (import.meta.client && !nuxtApp.isHydrating) {
// ...
}
})
}
})
runWithContext
runWithContext
方法旨在用于调用函数并为其提供显式的 Nuxt 上下文。 通常,Nuxt 上下文是隐式传递的,您无需担心。 但是,在中间件/插件中使用复杂的 async
/await
场景时,您可能会遇到在异步调用后当前实例已被取消设置的情况。
export default defineNuxtRouteMiddleware(async (to, from) => {
const nuxtApp = useNuxtApp()
let user
try {
user = await fetchUser()
// the Vue/Nuxt compiler loses context here because of the try/catch block.
} catch (e) {
user = null
}
if (!user) {
// apply the correct Nuxt context to our `navigateTo` call.
return nuxtApp.runWithContext(() => navigateTo('/auth'))
}
})
用法
const result = nuxtApp.runWithContext(() => functionWithContext())
functionWithContext
:任何需要当前 Nuxt 应用程序上下文的函数。 此上下文将自动正确应用。
runWithContext
将返回 functionWithContext
返回的任何内容。
上下文的更深入解释
Vue.js Composition API(以及类似的 Nuxt 组合式函数)通过依赖隐式上下文工作。 在生命周期中,Vue 将当前组件的临时实例(以及 nuxtApp 的 Nuxt 临时实例)设置为全局变量,并在同一 tick 中取消设置。 在服务器端渲染时,来自不同用户的多个请求和 nuxtApp 在同一全局上下文中运行。 因此,Nuxt 和 Vue 会立即取消设置此全局实例,以避免在两个用户或组件之间泄漏共享引用。
这意味着什么? Composition API 和 Nuxt 组合式函数仅在生命周期内以及任何异步操作之前的同一 tick 中可用
// --- Vue internal ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---
// Vue / Nuxt sets a global variable referencing to current component in _vueInstance when calling setup()
async function setup() {
getCurrentInstance() // Works
await someAsyncOperation() // Vue unsets the context in same tick before async operation!
getCurrentInstance() // null
}
对此的经典解决方案是在首次调用时将当前实例缓存到像 const instance = getCurrentInstance()
这样的局部变量中,并在下一个组合式函数调用中使用它,但问题是任何嵌套的组合式函数调用现在都需要显式地接受实例作为参数,而不是依赖 composition-api 的隐式上下文。 这是组合式函数的设计限制,而不是问题本身。
为了克服此限制,Vue 在编译我们的应用程序代码时做了一些幕后工作,并在每次调用 <script setup>
后恢复上下文
const __instance = getCurrentInstance() // Generated by Vue compiler
getCurrentInstance() // Works!
await someAsyncOperation() // Vue unsets the context
__restoreInstance(__instance) // Generated by Vue compiler
getCurrentInstance() // Still works!
有关 Vue 实际执行操作的更好描述,请参阅 unjs/unctx#2 (评论)。
解决方案
这就是可以使用 runWithContext
来恢复上下文的地方,类似于 <script setup>
的工作方式。
Nuxt 内部使用 unjs/unctx 来支持类似于 Vue 的插件和中间件的组合式函数。 这使得像 navigateTo()
这样的组合式函数无需直接将 nuxtApp
传递给它们即可工作 - 将 Composition API 的 DX 和性能优势带到整个 Nuxt 框架。
Nuxt 组合式函数与 Vue Composition API 具有相同的设计,因此需要类似的解决方案来神奇地进行此转换。 查看 unjs/unctx#2(提案)、unjs/unctx#4(转换实现)和 nuxt/framework#3884(集成到 Nuxt)。
Vue 目前仅支持为 <script setup>
中的 async/await 用法恢复异步上下文。在 Nuxt 3 中,添加了对 defineNuxtPlugin()
和 defineNuxtRouteMiddleware()
的转换支持,这意味着当您使用它们时,Nuxt 会自动转换它们并恢复上下文。
遗留问题
用于自动恢复上下文的 unjs/unctx
转换似乎在包含 await
的 try/catch
语句中存在缺陷,最终需要解决此问题,以便移除上述建议的变通方案的要求。
原生异步上下文
使用新的实验性功能,可以使用 Node.js AsyncLocalStorage
和新的 unctx 支持来启用原生异步上下文支持,从而使异步上下文原生可用于任何嵌套的异步组合函数,而无需转换或手动传递/使用上下文调用。
tryUseNuxtApp
此函数的工作方式与 useNuxtApp
完全相同,但如果上下文不可用,则返回 null
而不是抛出异常。
您可以将其用于不需要 nuxtApp
的组合函数,或者只是检查上下文是否可用而无需异常。
用法示例
export function useStandType() {
// Always works on the client
if (tryUseNuxtApp()) {
return useRuntimeConfig().public.STAND_TYPE
} else {
return process.env.STAND_TYPE
}
}