- Today
- Total
빵 입니다.
[nuxt] [useFetch] Component is already mounted, please use $fetch instead. 본문
[nuxt] [useFetch] Component is already mounted, please use $fetch instead.
bread-gee 2025. 2. 3. 16:17nuxt3를 이용해 포트폴리오 사이트를 만들면서 익혀보려고 마음을 먹었다.
틈틈이 시간날 때 셋팅하고 시작을 했고...
가볍게 라우팅✔
firebase 연결✔ (← 써보고 싶었음)
조금조금씩 위 내용들은 실행을 했다.
그러나 슬픈 예감은 틀리지 않지... (기초적인 학습을 안하고 안해서 그런 듯...)
API 통신 예제들을 적용해 보면서 외부 API와의 연결 셋팅까지만 해보려고 했는데 에러가 떴다.
📍 이 에러를 발생시킨 나의 코드
(Nuxt에선 Data fetching을 하는 데에 사용하는 몇 가지 메서드들이 있는데, 생각없이 냅다 useFetch를 써버리니까 뜬 에러입니다.)
<script setup>
import { ref } from 'vue';
const posts = ref([]);
const error = ref(null);
const pending = ref(false);
const fetchPosts = async () => {
pending.value = true;
error.value = null;
try {
posts.value = await useFetch('/api/posts'); // 여기를 보세요.
} catch (err) {
error.value = err;
} finally {
pending.value = false;
}
};
</script>
<template>
<button @click="fetchPosts">데이터 가져오기</button>
<div v-if="pending">로딩 중...</div>
<div v-else-if="error">오류 발생: {{ error.message }}</div>
<div v-else>
<ul>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
[nuxt] [useFetch] Component is already mounted, please use $fetch instead. See https://nuxt.com/docs/getting-started/data-fetching
useFetch는 서버사이드 렌더링에서 실행되는 fetch 함수인데 무지성으로 컴포넌트가 마운트된 후에 실행되기 때문에 발생한다.
그러므로 컴포넌트가 이미 마운트되었으니 useFetch 대신 $fetch를 사용하라는~~~
해결방법을 찾아보았는데용.
📌 해결 방법 1 : 클라이언트 사이드 이벤트 실행 시엔 fetch나 $fetch를 사용하기
fetch는 브라우저에서 제공하는 API 그것을 말하는 거고, $fetch는 Nuxt3에서 제공하는 메서드인데
둘 다 데이터를 가져오는 기능을 하지만, 동작 방식에 차이가 있다.
🧿 fetch는...
- headers, body 등을 직접 설정해야 한다.
- 에러를 자동으로 핸들링해주지 않으므로 response.ok를 체크해야 한다.
- 경로를 절대 경로로 지정해야 한다. 경로를 지정하지 않으면 현재 페이지의 도메인을 기준으로 데이터를 요청한다.
fetch('http://localhost:3000/api/posts') // 기본형
🧿 $fetch는...
- Nuxt 3 전용 기능, 자동으로 useRuntimeConfig() 반영해 준다.
- 에러 발생 시 자동으로 에러를 throw 해주기 때문에 따로 설정해야하는 번거로움이 적다. try-catch 사용 가능하다.
- baseURL을 자동으로 적용해 주기 때문에 상대 경로만 입력해도 된다.
- 무엇보다 장점은 $fetch 는 ofetch 라는 라이브러리를 사용하고 있는데, 실행환경에 따라 사용하는 라이브러리를 자동으로 바꿔서 사용한다고 한다. Node 환경에서 실행된다면 node-fetch-native을 사용하고, Browser 환경에서 실행된다면 Browser 의 fetch API 를 사용한다고 한다.
// $fetch('/api/posts') // 기본형
<script setup>
import { ref } from 'vue';
const posts = ref([]);
const error = ref(null);
const pending = ref(false);
const fetchPosts = async () => {
pending.value = true;
error.value = null;
try {
posts.value = await $fetch('/api/posts'); // 여기를 보세요.
} catch (err) {
error.value = err;
} finally {
pending.value = false;
}
};
</script>
<template>
<button @click="fetchPosts">데이터 가져오기</button>
<div v-if="pending">로딩 중...</div>
<div v-else-if="error">오류 발생: {{ error.message }}</div>
<div v-else>
<ul>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
📌 해결 방법 2 : useFetch를 onMounted 이전에 실행하기
- useFetch는 서버사이드 렌더링에서 실행되는 함수인데, 컴포넌트 마운트 후, 즉 컴포넌트가 모두 렌더링된 상태에서 비동기 요청이 발생하기 때문에 문제가 발생한다.
- 따라서 문제를 해결하려면 컴포넌트 마운트 후 호출하지 말고(onMounted 내에서 호출하거나), useFetch를 컴포넌트의 상단, <script setup> 블록에서 직접 호출하도록 하면 된다.
<script setup>
const { data, error, pending } = useFetch('/api/posts');
</script>
<template>
<div v-if="pending">로딩 중...</div>
<div v-else-if="error">오류 발생: {{ error.message }}</div>
<div v-else>
<ul>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
출처 및 참고
https://jongmin4943.tistory.com/entry/Nuxt3-fetch-useAsyncData-useFetch-%EC%9D%98-%EC%B0%A8%EC%9D%B4
+ 챗 GPT
🤙🏻 [나와의 약속] 조만간 Nuxt3에서 사용하는 Data fetching 방법에 대해 학습을 진득하게 시작해야겠다.