useNuxtApp
useNuxtApp
是一個內建的 composable,提供一種存取 Nuxt 共用執行階段上下文的方式,也稱為 Nuxt 上下文,它在客戶端和伺服器端都可用(但不在 Nitro 路由中)。它可以幫助您存取 Vue 應用程式實例、執行階段鉤子、執行階段配置變數和內部狀態,例如 ssrContext
和 payload
。
<script setup lang="ts">
const nuxtApp = useNuxtApp()
</script>
如果您的作用域中執行階段上下文不可用,則調用 useNuxtApp
時會拋出例外。您可以改用 tryUseNuxtApp
用於不需要 nuxtApp
的 composable,或者只是檢查上下文是否可用,而不會拋出例外。
方法
provide (name, value)
nuxtApp
是一個執行階段上下文,您可以使用 Nuxt 外掛模組 來擴展它。使用 provide
函數創建 Nuxt 外掛模組,以使值和輔助方法在您的 Nuxt 應用程式中的所有 composable 和組件中都可用。
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 composable 和 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
(字串) - 當前請求 URL。event
(unjs/h3 請求事件) - 存取當前路由的請求和回應。payload
(物件) - NuxtApp payload 物件。
payload
payload
將伺服器端的資料和狀態變數公開給客戶端。以下鍵在從伺服器端傳遞後將在客戶端上可用
serverRendered
(布林值) - 指示回應是否為伺服器端渲染。data
(物件) - 當您使用useFetch
或useAsyncData
從 API 端點獲取資料時,可以從payload.data
存取結果酬載。此資料會被快取,並協助您在多次發出相同請求時防止重複獲取相同的資料。<script setup lang="ts"> const { data } = await useAsyncData('count', () => $fetch('/api/count')) </script>
在上述範例中使用useAsyncData
獲取count
的值後,如果您存取payload.data
,您會看到{ count: 1 }
記錄在那裡。
當從ssrcontext
存取相同的payload.data
時,您也可以在伺服器端存取相同的值。state
(物件) - 當您在 Nuxt 中使用useState
composable 來設定共享狀態時,此狀態資料會透過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。
在以下範例中,我們為 Luxon DateTime 類別定義了一個 reducer(或序列化器)和一個 reviver(或反序列化器),使用了 payload plugin。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
(布林值) 來檢查 Nuxt 應用程式是否正在客戶端進行 hydration。
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (import.meta.client && !nuxtApp.isHydrating) {
// ...
}
})
}
})
runWithContext
runWithContext
方法旨在用於呼叫函式並給予它明確的 Nuxt context。通常,Nuxt context 會隱式地傳遞,您無需擔心這個問題。但是,當在 middleware/plugins 中使用複雜的 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 應用程式 context 的函式。此 context 將會自動正確地套用。
runWithContext
將會回傳 functionWithContext
所回傳的任何內容。
Context 的更深入解釋
Vue.js Composition API(以及 Nuxt composables 類似地)透過依賴隱式 context 來運作。在生命週期中,Vue 會將目前組件的臨時實例(以及 Nuxt nuxtApp 的臨時實例)設定為全域變數,並在相同的 tick 中取消設定。當在伺服器端渲染時,會有來自不同使用者的多個請求,並且 nuxtApp 在相同的全域 context 中執行。因此,Nuxt 和 Vue 會立即取消設定此全域實例,以避免在兩個使用者或組件之間洩漏共享參考。
這意味著什麼?Composition API 和 Nuxt Composables 僅在生命週期期間以及任何非同步操作之前的相同 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()
這樣的區域變數中,並在下一個 composable 呼叫中使用它,但問題是任何巢狀的 composable 呼叫現在都需要明確地接受實例作為參數,而不是依賴 composition-api 的隱式 context。這是 composables 的設計限制,本身不是問題。
為了克服這個限制,Vue 在編譯我們的應用程式碼時做了一些幕後工作,並在每次 <script setup>
呼叫後還原 context。
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 (comment)。
解決方案
這就是可以使用 runWithContext
來還原 context 的地方,類似於 <script setup>
的運作方式。
Nuxt 內部使用 unjs/unctx 來支援類似於 Vue 的 plugins 和 middleware 的 composables。這使得像 navigateTo()
這樣的 composables 可以在不直接將 nuxtApp
傳遞給它們的情況下工作 - 將 Composition API 的 DX 和效能優勢帶到整個 Nuxt 框架。
Nuxt composables 的設計與 Vue Composition API 相同,因此需要類似的解決方案來神奇地進行這種轉換。查看 unjs/unctx#2 (提案)、unjs/unctx#4 (轉換實作) 和 nuxt/framework#3884 (整合到 Nuxt)。
Vue 目前僅支援 <script setup>
的非同步 context 還原,用於 async/await 用法。在 Nuxt 3 中,新增了對 defineNuxtPlugin()
和 defineNuxtRouteMiddleware()
的轉換支援,這表示當您使用它們時,Nuxt 會自動使用 context 還原轉換它們。
剩餘問題
用於自動還原 context 的 unjs/unctx
轉換在包含 await
的 try/catch
語句中似乎有錯誤,這最終需要解決,以便消除上述建議的變通方法的必要性。
原生非同步 Context
使用新的實驗性功能,可以使用 Node.js AsyncLocalStorage
和新的 unctx 支援來啟用原生非同步 context 支援,以使非同步 context 原生 地提供給任何巢狀非同步 composable,而無需轉換或手動傳遞/使用 context 呼叫。
tryUseNuxtApp
此函式的作用與 useNuxtApp
完全相同,但如果 context 不可用,則會回傳 null
,而不是拋出例外。
您可以將其用於不需要 nuxtApp
的 composables,或僅用於檢查 context 是否可用,而無需例外。
使用範例
export function useStandType() {
// Always works on the client
if (tryUseNuxtApp()) {
return useRuntimeConfig().public.STAND_TYPE
} else {
return process.env.STAND_TYPE
}
}