빵 입니다.

[nuxt] [useFetch] Component is already mounted, please use $fetch instead. 본문

프론트엔드/Nuxt3

[nuxt] [useFetch] Component is already mounted, please use $fetch instead.

bread-gee 2025. 2. 3. 16:17
반응형

nuxt3를 이용해 포트폴리오 사이트를 만들면서 익혀보려고 마음을 먹었다.

틈틈이 시간날 때 셋팅하고 시작을 했고...

가볍게 라우팅✔

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>

useFetch 에러

 

[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

https://medium.com/@awhekdns/nuxt3-api-%ED%98%B8%EC%B6%9C%ED%95%98%EA%B8%B0-fetch-asyncdata-usefetch-8124faed61ba

+ 챗 GPT

 

 

 

 


🤙🏻 [나와의 약속] 조만간 Nuxt3에서 사용하는 Data fetching 방법에 대해 학습을 진득하게 시작해야겠다.

 

반응형
Comments