같은 API를 두 컴포넌트에서 부르니 요청도 두 번 나간 이유
문제 발생
헤더와 사이드바가 같은 프로필 API를 각각 불렀습니다.
<!-- AppHeader.vue -->
<script setup>
const { data: me } = await useFetch("/api/me");
</script>
<!-- AppSidebar.vue -->
<script setup>
const { data: me } = await useFetch("/api/me");
</script>URL이 같은데도 네트워크 탭에는 요청이 두 번 찍혔고, 한쪽에서 refresh()를 불러도 다른 쪽 값은 그대로였습니다.
원인 분석
키가 다르기 때문입니다. Nuxt 문서는 키 생성 방식을 이렇게 설명합니다 — useFetch는 URL, fetch 옵션, 그리고 호출 위치로 키를 만들고, useAsyncData는 첫 인자가 문자열이면 그것을 키로 쓰고 아니면 호출 위치로 만듭니다.
호출 위치가 키에 들어가므로 파일이 다르면 URL이 같아도 다른 키가 됩니다. 그래서 캐시가 공유되지 않고 각자 요청합니다.
문서의 해법도 한 줄입니다 — 여러 컴포넌트에서 같은 데이터를 공유하려면 같은 명시적 key를 주라는 것입니다. 그렇게 하면 useNuxtData로 그 키의 데이터를 다른 곳에서 읽거나 갱신할 수도 있습니다.
해결 방안
- 키를 명시합니다. 두 컴포넌트가 같은 캐시 항목을 봅니다.
const { data: me } = await useFetch("/api/me", { key: "me" });- 더 나은 방법은 컴포저블 하나로 감싸는 것입니다. 키와 옵션이 한 곳에만 있으면 어긋날 일이 없습니다.
// composables/useMe.ts
export function useMe() {
return useFetch("/api/me", { key: "me" });
}- URL이 반응형이면 콜백으로 넘깁니다. 문서 설명대로 URL 문자열을 반환하는 computed getter 형태의 콜백을 쓰면 의존하는 값이 바뀔 때마다 다시 가져옵니다. 문자열 템플릿으로 한 번 평가된 값을 넘기면 그 뒤로 갱신되지 않습니다.
const { data } = await useFetch(() => `/api/posts/${id.value}`);-
$fetch를 setup에서 직접 부르지 않습니다. 문서가 지적하는 그대로 — setup 함수 안에서$fetch로 데이터를 가져오면 서버에서 HTML을 만들 때 한 번, 클라이언트에서 다시 한 번, 두 번 요청될 수 있습니다. 컴포저블은 서버에서 가져온 데이터를 payload로 클라이언트에 넘겨 이 중복을 막습니다. -
다른 곳에서 이미 받은 값을 다시 읽을 때는
useNuxtData입니다. 새 요청 없이 캐시된 값에 접근합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.