SSR 및 SvelteKit
설정
SvelteKit는 기본적으로 SSR을 사용하여 라우트를 렌더링합니다. 이 때문에 서버에서 쿼리를 비활성화해야 합니다. 그렇지 않으면 HTML이 클라이언트에 전송된 후에도 쿼리가 서버에서 비동기적으로 계속 실행됩니다.
이를 구현하는 권장 방법은 QueryClient 객체에서 SvelteKit의 browser 모듈을 사용하는 것입니다. 이렇게 해도 아래 해결책 중 하나에서 사용하는 queryClient.query()는 비활성화되지 않습니다.
src/routes/+layout.svelte
<script lang="ts">
import { browser } from '$app/environment'
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
enabled: browser,
},
},
})
</script>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>
데이터 프리페치
Svelte Query는 서버에서 데이터를 프리페치하고 SvelteKit을 사용해 이를 클라이언트에 전달하는 두 가지 방식을 지원합니다.
이상적인 SSR 설정을 확인하려면 SSR 예제를 살펴보세요.
initialData 사용하기
SvelteKit의 load과 함께 사용하면 서버 측에서 로드한 데이터를 createQuery의 initialData 옵션에 전달할 수 있습니다:
src/routes/+page.ts
export async function load() {
const posts = await getPosts()
return { posts }
}
src/routes/+page.svelte
<script>
import { createQuery } from '@tanstack/svelte-query'
import type { PageData } from './$types'
export let data: PageData
const query = createQuery(() => ({
queryKey: ['posts'],
queryFn: getPosts,
initialData: data.posts,
}))
</script>
장점:
- 이 설정은 최소한으로 구성되어 있으며 일부 사례에서는 빠른 해결책이 될 수 있습니다
+page.ts/+layout.ts및+page.server.ts/+layout.server.ts로드 함수 모두에서 작동합니다
단점:
- 트리의 더 깊은 곳에 있는 컴포넌트에서
createQuery를 호출한다면initialData를 그 지점까지 전달해야 합니다 - 여러 위치에서 동일한 쿼리로
createQuery를 호출하는 경우 모든 호출에initialData를 전달해야 합니다 - 서버에서 쿼리를 가져온 시점을 알 방법이 없으므로, 대신
dataUpdatedAt및 쿼리를 다시 가져와야 하는지에 대한 판단은 페이지가 로드된 시점을 기준으로 합니다
query 사용하기
Svelte Query는 서버에서 쿼리를 프리페치하는 기능을 지원합니다. 아래 설정을 사용하면 데이터를 가져와 사용자의 브라우저로 전송하기 전에 QueryClientProvider에 전달할 수 있습니다. 따라서 이 데이터는 이미 캐시에 있으며 클라이언트 측에서 초기 가져오기가 발생하지 않습니다.
src/routes/+layout.ts
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'
export async function load() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
enabled: browser,
},
},
})
return { queryClient }
}
src/routes/+layout.svelte
<script lang="ts">
import { QueryClientProvider } from '@tanstack/svelte-query'
import type { LayoutData } from './$types'
export let data: LayoutData
</script>
<QueryClientProvider client={data.queryClient}>
<slot />
</QueryClientProvider>
src/routes/+page.ts
export async function load({ parent, fetch }) {
const { queryClient } = await parent()
// You need to use the SvelteKit fetch function here
await queryClient
.query({
queryKey: ['posts'],
queryFn: async () => (await fetch('/api/posts')).json(),
})
.catch(noop)
}
src/routes/+page.svelte
<script lang="ts">
import { createQuery } from '@tanstack/svelte-query'
// This data is cached by query in +page.ts so no fetch actually happens here
const query = createQuery(() => ({
queryKey: ['posts'],
queryFn: async () => (await fetch('/api/posts')).json(),
}))
</script>
장점:
- 서버에서 로드된 데이터는 prop drilling 없이 어디서든 접근할 수 있습니다.
- 쿼리 캐시가
dataUpdatedAt을 포함하여 수행된 쿼리에 관한 모든 정보를 유지하므로, 페이지가 렌더링된 후에는 클라이언트 측에서 초기 가져오기가 발생하지 않습니다
단점:
- 초기 설정에 더 많은 파일이 필요합니다
+page.server.ts/+layout.server.ts로드 함수에서는 작동하지 않습니다(하지만 TanStack Query와 함께 사용되는 API는 어차피 브라우저에 완전히 노출되어야 합니다)