[Nuxt3] SSR CSR Hydration - Data fetching 효율적으로 하기
서버 사이드 렌더링 (SSR)
Nuxt는 서버에서 HTML을 미리 렌더링하여 클라이언트에 전달한다.
서버는 클라이언트가 필요한 데이터를 미리 가져와서 HTML에 포함시키고, 이 HTML이 브라우저에 전달되면 사용자가 페이지를 바로 볼 수 있게 된다. 이 과정에서 데이터는 서버에서 한 번 가져와 HTML에 렌더링된다.
클라이언트 하이드레이션:
클라이언트는 서버로부터 받은 HTML을 하이드레이션(Hydration)이라는 과정을 통해 Vue.js 애플리케이션으로 연결한다.
하이드레이션 과정 > 클라이언트 사이드에서 Vue 컴포넌트가 초기화되고, 각 컴포넌트는 자신이 필요한 데이터를 다시 가져오려 할 수 있다.
만약 클라이언트가 하이드레이션 시에 별도로 데이터를 가져오는 함수 ($fetch 같은 비동기 데이터 로딩 함수)를 사용한다면, 서버에서 이미 데이터를 가져왔음에도 불구하고 클라이언트에서 다시 한 번 데이터를 요청하게 된다.
이렇게 두 번 데이터를 가져오는 이유는 서버가 HTML을 렌더링할 때 한 번 데이터를 가져오고, 클라이언트가 하이드레이션될 때 또 한 번 데이터를 가져오기 때문이다.
Nuxt는 서버와 클라이언트 환경 모두에서 코드를 실행하며 이로인해 data fetching에 문제가 생기게된다.
- 동형(범용) 코드: Nuxt는 서버와 클라이언트 양쪽에서 같은 코드를 실행할 수 있는 동형 또는 범용 프레임워크이다.
즉, 서버에서 페이지를 미리 렌더링(SSR, Server-Side Rendering)하고, 클라이언트에서는 이를 이어받아 인터랙션을 처리할 수 있다. - $fetch 함수의 역할: $fetch는 Nuxt에서 데이터를 가져오는 비동기 함수이다. Vue 컴포넌트의 setup 함수에서 $fetch를 사용하면, 서버와 클라이언트에서 각각 한 번씩 데이터를 가져올 수 있다.
- 두 번의 데이터 가져오기 문제: 서버에서 HTML을 렌더링할 때 한 번 데이터를 가져오고, 클라이언트가 이 HTML을 하이드레이션(SSR로 렌더된 HTML을 클라이언트 측 Vue로 연결하는 과정)할 때 다시 한 번 데이터를 가져오는 상황이 발생할 수 있다. 이 경우, 데이터를 두 번 가져와 비효율적이다.
- Nuxt의 해결책: Nuxt는 이러한 문제를 해결하기 위해 데이터 페칭 컴포저블(composable : useAsyncData, useFetch)을 제공한다. 이 컴포저블은 데이터를 한 번만 가져와서 서버와 클라이언트가 이를 공유할 수 있도록 관리해, 중복된 데이터 요청을 피할 수 있다.
두 번 데이터를 가져오는 예시
<template>
<div>
<h1>Fetched Data</h1>
<pre>{{ data }}</pre>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 데이터 저장 변수
const data = ref(null)
// 데이터를 가져오는 함수
const fetchData = async () => {
data.value = await $fetch('https://api.example.com/data')
}
// setup 함수에서 데이터 페칭 호출
fetchData()
</script>
한 번만 데이터를 가져오는 예시
<template>
<div>
<h1>Fetched Data</h1>
<pre>{{ data }}</pre>
</div>
</template>
<script setup>
// useFetch를 사용하여 데이터 페칭
const { data } = useFetch('https://api.example.com/data')
</script>
setup에 선언된 변수는 두 번 초기화될까?
setup 함수 내에서 선언된 변수는 두 번 할당되며 이는 두 번 초기화 됨을 의미한다.
<script setup>
let test = ref(0)
const { data } = await useAsyncData('counter', () => {
return ref(0); // 초기값을 설정
})
test = data
</script>
위의 코드는 아래와 같이 동작한다.
- 서버 사이드 렌더링 (SSR)
- SSR에서 setup 함수가 처음 호출될 때, test는 처음에 ref(0)으로 초기화 된다.
- 이후 useAsyncData가 호출되어 데이터를 가져오면서 data가 반환되고, test는 data로 다시 할당된다.
- 이 시점에서 test는 data의 값으로 설정되며, Nuxt는 서버에서 데이터를 가져와 렌더링한 HTML을 클라이언트에 전달한다.
- 클라이언트 사이드 하이드레이션 (CSR)
- 클라이언트에서 하이드레이션이 시작될 때, setup 함수가 다시 실행됩니다.
- 이때 test는 초기값으로 다시 ref(0)으로 설정됩니다.
- 하지만 useAsyncData가 클라이언트에서도 동일하게 호출되고, Nuxt는 서버에서 가져온 데이터를 캐싱해서 클라이언트에서 다시 가져오지 않고 같은 데이터를 사용한다.
- 따라서 data는 서버에서 가져온 값이므로, test가 다시 data로 할당되면 서버에서 받아온 값이 유지된다.
결론적으로 test는 CSR에서 잠시 초기값(0)으로 설정되었다가, useAsyncData에 의해 서버에서 받은 데이터로 다시 설정되기 때문에, 최종적으로는 SSR과 같은 데이터를 사용하게 된다.