로딩 표시 최적화를 위해 로딩이 1초 이상일 때만 useLoadingStore().show()
로 로딩 스피너를 표시하였다.
문제는 새로고침을 하면(SSR) Nuxt의 $fetch API에 문제가 생겨서 데이터 요청을 하지 않는다.
⬇️에러 메시지⬇️
[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function.
최적화 후 문제가 생겨서 이전 코드와 비교를 진행했다. 전에는 onRequest에서 스토어 초기화 및 실행을 반드시 진행하였다.
// before
onRequest({ options }) {
useLoadingStore().show() 🚩
options.headers = {생략}
},
onResponse() {
useLoadingStore().hide()
},
// after
onRequest({ options }) {
options.headers = {생략}
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
useLoadingStore().show() 🚩
}, 1000)
},
onResponse() {
if (timer) clearTimeout(timer)
useLoadingStore().hide()
},
하지만 현재 코드는 요청이 1초가 지나지 않으면 스토어 초기화 및 실행을 하지 않는다. onResponse에서 초기화가 되면 문제가 생기는 것이였다.
$fetch 외부와 onRequest에서 초기화하니 정상 동작하였다. 또는 runWithContext를 사용해 Nuxt 컨텍스트를 복원할 수 있다.
서버에서 사용할 필요가 없는 경우 클라이언트에서만 스토어에 접근하게 하면 된다.
onResponse에서 Nuxt 컨텍스트 사용하는 방법 4가지
로딩은 서버에서 렌더링될 필요가 없어서 분기처리 하면 해결된다. 하지만 서버 렌더링에서 Nuxt컨텍스트가 필요하다면 1~3번 방식을 이용하면 된다.
onResponse에서 Nuxt 컨텍스트와 Nuxt 컴포저블 참조는 가능하나, 이를 생성하면 SSR 환경에서 오류가 발생할 수 있다.
setup(), useFetch(), useAsyncData() 등은 클라이언트와 서버에서 실행될 때 Nuxt 컨텍스트에 접근할 수 있다. 하지만 Nitro 미들웨어(onRequest, onResponse 등)에서는 SSR 환경에서 실행될 때 Nuxt 컨텍스트를 유지하지 않는다.
따라서 useFetch() 내부에서 인터셉터(onRequest, onResponse…)를 사용할 경우, 클라이언트와 서버에서 동작 방식이 다르다는 것을 인지하고 개발해야 한다.
useNuxtApp은 클라이언트 및 서버 측에서 모두 사용할 수 있는(Nitro 라우트 내에서는 사용할 수 없음) Nuxt의 공유 런타임 컨텍스트에 액세스하는 방법을 제공하는 내장 컴포저블입니다(Nuxt 컨텍스트라고도 함). Vue 앱 인스턴스, 런타임 훅, 런타임 구성 변수 및 내부 상태(예: ssrContext 및 페이로드)에 액세스하는 데 도움이 됩니다.
const $customFetch = async (url, opts) => {
const loadingStroe = useLoadingStore() 🚩
let timer: NodeJS.Timeout | null = null
return await $fetch({생략}, {
...opts,
onRequest() {
if(import.meta.client){ 🚩
if (timer) clearTimeout(timer)
timer = setTimeout(() => useLoadingStore().show(), 1000)}
},
onResponse() {
if(import.meta.client){ 🚩
if (timer) clearTimeout(timer)
useLoadingStore().hide()
}
},
})
}