useNuxtApp
访问 Nuxt 应用程序的共享运行时上下文。
useNuxtApp
是一个内置的可组合函数,提供了一种访问 Nuxt 共享运行时上下文的方法,也称为 Nuxt 上下文,它在客户端和服务器端都可用(但不在 Nitro 路由中)。它帮助您访问 Vue 应用实例、运行时钩子、运行时配置变量和内部状态,例如 ssrContext
和 payload
。
const nuxtApp = useNuxtApp()
如果在您的范围内运行时上下文不可用,调用 useNuxtApp
时将抛出异常。您可以使用 tryUseNuxtApp
代替不需要 nuxtApp
的可组合函数,或者简单地检查上下文是否可用而不抛出异常。
方法
provide (name, value)
nuxtApp
是一个可以使用 Nuxt 插件 扩展的运行时上下文。使用 provide
函数创建 Nuxt 插件,以便在您的 Nuxt 应用程序中跨所有可组合函数和组件提供值和辅助方法。
provide
函数接受 name
和 value
参数。
const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', (name) => `Hello ${name}!`)
// 打印 "Hello name!"
console.log(nuxtApp.$hello('name'))
如上例所示,$hello
已成为 nuxtApp
上下文的新自定义部分,并且在所有可以访问 nuxtApp
的地方都可用。
hook(name, cb)
nuxtApp
中可用的钩子允许您自定义 Nuxt 应用程序的运行时方面。您可以在 Vue.js 可组合函数和 Nuxt 插件 中使用运行时钩子来挂钩到渲染生命周期。
hook
函数用于通过在特定点挂钩到渲染生命周期来添加自定义逻辑。hook
函数主要用于创建 Nuxt 插件时。
请参阅 Runtime Hooks 以获取 Nuxt 调用的可用运行时钩子。
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
/* 在这里编写您的代码 */
})
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
(字符串) - 当前请求的 URL。event
(h3js/h3 请求事件) - 访问当前路由的请求和响应。payload
(对象) - NuxtApp 负载对象。
payload
payload
从服务器端向客户端公开数据和状态变量。以下键将在从服务器端传递后在客户端可用:
-
serverRendered
(布尔值) - 指示响应是否为服务器端渲染。 -
data
(对象) - 当您使用useFetch
或useAsyncData
从 API 端点获取数据时,结果负载可以从payload.data
访问。此数据被缓存,帮助您防止在相同请求多次发出时重复获取相同数据。const { data } = await useAsyncData('count', () => $fetch('/api/count'))
在上面的示例中使用
useAsyncData
获取count
的值后,如果您访问payload.data
,您将看到{ count: 1 }
记录在那里。当从
ssrcontext
访问相同的payload.data
时,您也可以在服务器端访问相同的值。 -
state
(对象) - 当您在 Nuxt 中使用useState
可组合函数设置共享状态时,此状态数据通过payload.state.[name-of-your-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。
在下面的示例中,我们使用负载插件为 Luxon DateTime 类定义一个 reducer(或序列化器)和一个 reviver(或反序列化器)。
plugins/date-time-payload.ts/** * 这种类型的插件在 Nuxt 生命周期中非常早运行,在我们恢复负载之前。 * 您将无法访问路由器或其他 Nuxt 注入的属性。 * * 请注意,“DateTime”字符串是类型标识符,必须在 reducer 和 reviver 中相同。 */ export default definePayloadPlugin((nuxtApp) => { definePayloadReducer('DateTime', (value) => { return value instanceof DateTime && value.toJSON() }) definePayloadReviver('DateTime', (value) => { return DateTime.fromISO(value) }) })
isHydrating
使用 nuxtApp.isHydrating
(布尔值) 检查 Nuxt 应用程序是否在客户端进行水合。
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (import.meta.client && !nuxtApp.isHydrating) {
// ...
}
})
}
})
runWithContext
您可能在这里是因为您收到“Nuxt 实例不可用”消息。请谨慎使用此方法,并报告导致问题的示例,以便最终在框架级别解决。
runWithContext
方法用于调用一个函数并为其提供显式的 Nuxt 上下文。通常,Nuxt 上下文是隐式传递的,您无需担心这一点。然而,在中间件/插件中处理复杂的 async
/await
场景时,您可能会遇到在异步调用后当前实例已被取消设置的情况。
export default defineNuxtRouteMiddleware(async (to, from) => {
const nuxtApp = useNuxtApp()
let user
try {
user = await fetchUser()
// 由于 try/catch 块,Vue/Nuxt 编译器在这里丢失了上下文。
} catch (e) {
user = null
}
if (!user) {
// 为我们的 `navigateTo` 调用应用正确的 Nuxt 上下文。
return nuxtApp.runWithContext(() => navigateTo('/auth'))
}
})
用法
const result = nuxtApp.runWithContext(() => functionWithContext())
functionWithContext
: 任何需要当前 Nuxt 应用程序上下文的函数。此上下文将自动正确应用。
runWithContext
将返回 functionWithContext
返回的任何内容。
上下文的更深层解释
Vue.js 组合 API(以及类似的 Nuxt 可组合函数)通过依赖于隐式上下文来工作。在生命周期期间,Vue 将当前组件的临时实例(以及 Nuxt 的临时 nuxtApp 实例)设置为全局变量,并在同一 tick 中取消设置它。在服务器端渲染时,有来自不同用户的多个请求,并且 nuxtApp 在同一全局上下文中运行。因此,Nuxt 和 Vue 立即取消设置此全局实例,以避免在两个用户或组件之间泄漏共享引用。
这意味着什么?组合 API 和 Nuxt 可组合函数仅在生命周期期间和异步操作之前的同一 tick 中可用:
// --- Vue 内部 ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---
// Vue / Nuxt 在调用 setup() 时设置一个全局变量引用当前组件到 _vueInstance
async function setup() {
getCurrentInstance() // 有效
await someAsyncOperation() // Vue 在异步操作之前的同一 tick 中取消设置上下文!
getCurrentInstance() // null
}
经典解决方案是在第一次调用时将当前实例缓存到本地变量中,如 const instance = getCurrentInstance()
,并在下一个可组合调用中使用它,但问题是任何嵌套的可组合调用现在需要显式接受实例作为参数,而不是依赖于组合 API 的隐式上下文。这是可组合函数的设计限制,而不是一个问题。
为了解决这个限制,Vue 在编译我们的应用程序代码时在幕后进行一些工作,并在每次调用后恢复 <script setup>
的上下文:
const __instance = getCurrentInstance() // 由 Vue 编译器生成
getCurrentInstance() // 有效!
await someAsyncOperation() // Vue 取消设置上下文
__restoreInstance(__instance) // 由 Vue 编译器生成
getCurrentInstance() // 仍然有效!
有关 Vue 实际执行的更好描述,请参阅 unjs/unctx#2 (comment)。
解决方案
这就是 runWithContext
可以用来恢复上下文的地方,类似于 <script setup>
的工作方式。
Nuxt 内部使用 unjs/unctx 来支持类似于 Vue 的插件和中间件的可组合函数。这使得像 navigateTo()
这样的可组合函数可以在不直接传递 nuxtApp
给它们的情况下工作 - 将组合 API 的 DX 和性能优势带给整个 Nuxt 框架。
Nuxt 可组合函数的设计与 Vue 组合 API 相同,因此需要类似的解决方案来神奇地进行这种转换。查看 unjs/unctx#2(提案)、unjs/unctx#4(转换实现)和 nuxt/framework#3884(集成到 Nuxt)。
Vue 目前仅支持 <script setup>
的异步上下文恢复用于 async/await 使用。在 Nuxt 中,添加了 defineNuxtPlugin()
和 defineNuxtRouteMiddleware()
的转换支持,这意味着当您使用它们时,Nuxt 会自动将它们转换为上下文恢复。
剩余问题
unjs/unctx
转换在包含 await
的 try/catch
语句中自动恢复上下文似乎存在问题,这最终需要解决以消除上述解决方法的要求。
原生异步上下文
使用一个新的实验性功能,可以使用 Node.js AsyncLocalStorage
和新的 unctx 支持启用原生异步上下文支持,使异步上下文在 任何嵌套的异步可组合函数 中 原生 可用,而无需转换或手动传递/调用上下文。
原生异步上下文支持目前在 Bun 和 Node 中工作。
tryUseNuxtApp
此函数的工作方式与 useNuxtApp
完全相同,但如果上下文不可用,则返回 null
而不是抛出异常。
您可以将其用于不需要 nuxtApp
的可组合函数,或者简单地检查上下文是否可用而不抛出异常。
示例用法:
export function useStandType() {
// 始终在客户端上工作
if (tryUseNuxtApp()) {
return useRuntimeConfig().public.STAND_TYPE
} else {
return process.env.STAND_TYPE
}
}