useNuxtApp 은 클라이언트 측과 서버 측 모두에서 사용할 수 있는 Nuxt의 공유 런타임 컨텍스트에 액세스하는 방법을 제공하는 내장 컴포저블이다. Vue 앱 인스턴스, 런타임 후크, 런타임 구성 변수 및 내부 상태(예: ssrContext 및 payload) 에 액세스하는 데 도움이 됩니다.
<!--
app.vue
-->
<script setup lang="ts">
const nuxtApp = useNuxtApp()
</script>
Method
provide(name, value)
nuxtApp 은 Nuxt 플러그인을 사용하여 확장할 수 있는 런타임 컨텍스트이다. 이 provide 함수를 사용하여 Nuxt 플러그인을 생성하면 모든 컴포저블과 구성요소에서 Nuxt 애플리케이션에서 사용할 수 있는 값과 도우미 메서드를 만들 수 있다.
const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', (name) => `Hello ${name}!`)
// Prints "Hello name!"
console.log(nuxtApp.$hello('name'))
hook(name, cb)
nuxtApp 에서 사용 가능한 후크를 사용하면 Nuxt 애플리케이션의 런타임 측면을 사용자 정의할 수 있다. Vue.js 컴포저블 및 Nuxt 플러그인의 런타임 후크를 사용하여 렌더링 수명 주기에 연결할 수 있다.
hook 함수는 특정 지점에서 렌더링 수명주기에 연결하여 사용자 정의 논리를 추가하는 데 유용하다. hook함수는 Nuxt 플러그인을 만들 때 주로 사용된다.
Nuxt가 호출하는 사용 가능한 런타임 후크를 참고하면 된다.
// plugins/test.ts
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
/* your code goes here */
})
nuxtApp.hook('vue:error', (..._args) => {
console.log('vue:error')
// if (process.client) {
// console.log(..._args)
// }
})
})
callHook(name, ...args)
callHook 는 기존 후크를 사용하여 호출하면 프라미스를 반환한다.
await nuxtApp.callHook('my-plugin:init')
속성
useNuxtApp() 은 앱을 확장 및 사용자 지정하고 상태, 데이터 및 변수를 공유하는 데 사용할 수 있는 다음 속성을 노출한다.
- vueApp : nuxtApp 를 통해 액세스할 수 있는 전역 Vue.js 애플리케이션 인스턴스 입니다.
다음과 같은 메서드가 있습니다.- component() - 이름 문자열과 구성요소 정의를 모두 전달하는 경우 전역 구성요소를 등록하고, 이름만 전달하는 경우 이미 등록된 구성요소를 검색한다
- directive() - 이름 문자열과 지시어 정의를 모두 전달하는 경우 전역 사용자 지정 지시어를 등록하고, 이름만 전달하는 경우 이미 등록된 지시어를 검색한다.
- use() - Vue.js 플러그인을 설치한다.
- ssrContext
ssrContext 는 서버측 렌더링 중에 생성되며 서버 측에서만 사용할 수 있다.
Nuxt 는 ssrContext 를 통해 다음 속성을 노출한다.- url (string) - 현재 요청 URL
- event (unjs/h3 request event) - 현재 경로의 요청 및 응답에 액세스한다.
- payload (object) - NuxtApp 페이로드 객체
- payload : payload 는 서버 측에서 클라이언트 측으로 데이터 및 상태 변수를 노출한다. 다음 키는 서버 측에서 전달된 후 클라이언트에서 사용할 수 있다.
- serverRendered(boolean) - 응답이 서버 측에서 렌더링되는지 여부를 나타낸다.
- data(object) - useFetch 또는 useAsyncData 를 사용하여 API 엔드포인트에서 데이터를 가져오는 경우 결과 페이로드는 payload.data 에서 액세스할 수 있습니다 . 이 데이터는 캐시되어 동일한 요청이 두 번 이상 이루어지는 경우 동일한 데이터를 가져오는 것을 방지하는데 도움이 된다.
<!--
app.vue
-->
<script setup lang="ts">
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>
// server/api/counts.ts
export default defineEventHandler(event => {
return { count: 1 }
})
위 예시에서 useAsyncData 를 통해 count 값을 가져온 후, payload.data 에 접근해서 { count : 1} 레코드에 접근 할 수 있다. ssrContext를 통해 서버 측에서도 동일한 값에 액세스할 수 있다.
- state(object) - Nuxt에서 useState 컴포저블을 사용하여 공유 상태를 설정할 때 이 상태 데이터는 payload.state.[name-of-your-state] 를 통해 액세스된다.
// plugins/my-plugin.ts
export const useColor = () => useState<string>('color', () => 'pink')
export default defineNuxtPlugin((nuxtApp) => {
if (process.server) {
const color = useColor()
}
})
ref, reactive, shallowRef, shallowReactive 및 NuxtError 와 같은 고급 유형을 사용하는 것도 가능하다 .
Nuxt v3.4 부터 Nuxt에서 지원하지 않는 유형에 대해 자체 직렬 변환기/역직렬 변환기를 정의하는 것이 가능하다.
아래 예에서는 Luxon DateTime 클래스에 대한 직렬 변환기를 정의한다.
// 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 : isHydratingNuxt(boolean)을 사용하여 nuxtApp 앱이 클라이언트 측에서 하이드레이션 되고 있는지 확인 한다.
// components/nuxt-error-boundary.ts
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (process.client && !nuxtApp.isHydrating) {
// ...
}
})
}
})
- runWithContext : runWithContext 메소드는 함수를 호출하고 명시적인 Nuxt 컨텍스트를 제공하는 데 사용된다. 일반적으로 Nuxt 컨텍스트는 암시적으로 전달되므로 이에 대해 걱정할 필요가 없다. 그러나 미들웨어/플러그인에서 복잡한 async/ await시나리오로 작업할 때 비동기 호출 후 현재 인스턴스가 해제된 채 실행될 수 있다.
// middleware/auth.ts
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 는 functionWidthContext 에서 반환한 값이 무엇이든 반환한다.
컨텍스트에 대한 깊은 이해
Vue.js Composition API(및 유사하게 Nuxt 컴포저블)는 암시적 컨텍스트에 따라 작동한다. 라이프사이클 동안 Vue는 현재 구성요소의 임시 인스턴스(및 nuxtApp의 Nuxt 임시 인스턴스)를 전역 변수로 설정하고 동일한 틱에서 설정을 해제한다. 서버 측에서 렌더링할 때 동일한 전역 컨텍스트에서 실행되는 서로 다른 사용자 및 nuxtApp 으로부터의 여러 요청이 있을 수 있. 이로 인해 Nuxt와 Vue는 두 사용자 또는 컴포넌트간의 공유 참조로 인한 누출을 방지하기 위해 이 전역 인스턴스를 즉시 설정 해제한다.
이것이 의미하는 바는 Composition API 및 Nuxt 컴포저블은 수명 주기 동안 및 비동기 작업 전 동일한 틱에서만 사용할 수있다는 것이다.
// --- 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!
해결책
runWithContext 작동 방식과 유사하게 컨텍스트를 복원하는 데 사용할 수 있는 곳은 <script setup> 이다.
Nuxt 3는 내부적으로 unjs/unctx를 사용하여 플러그인 및 미들웨어용 Vue와 유사한 컴포저블을 지원한다. 이를 통해 컴포저블은 navigateTo() 직접 전달하지 않고도 작동할 수 있으며 nuxtAppComposition 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 지원을 사용하여 기본 비동기 컨텍스트 지원을 활성화하여 변환이나 컨텍스트를 통한 수동 전달/호출 없이 중첩된 비동기 컴포저블 에서 기본적으로 비동기 컨텍스트를 사용할 수 있다.
참고) Docs > Guide > Going Further > Experimental Feature#asynccontext
'Nuxt 공식문서 번역 > Composables' 카테고리의 다른 글
useRequestEvent (0) | 2023.12.14 |
---|---|
useNuxtData (0) | 2023.12.14 |
useLazyFetch (0) | 2023.12.14 |
useLazyAsyncData (0) | 2023.12.14 |
useHydration (0) | 2023.12.14 |