본문으로 건너뛰기

빠른 시작

@tanstack/solid-query 패키지는 SolidJS와 함께 TanStack Query를 사용하기 위한 일급 API를 제공합니다.

예시

import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/solid-query'
import { Switch, Match, For } from 'solid-js'

const queryClient = new QueryClient()

function Example() {
const query = useQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodos,
}))

return (
<div>
<Switch>
<Match when={query.isPending}>
<p>Loading...</p>
</Match>
<Match when={query.isError}>
<p>Error: {query.error.message}</p>
</Match>
<Match when={query.isSuccess}>
<For each={query.data}>{(todo) => <p>{todo.title}</p>}</For>
</Match>
</Switch>
</div>
)
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}

Solid Query와 React Query의 중요한 차이점

Solid Query는 React Query와 유사한 API를 제공하지만, 유의해야 할 몇 가지 핵심 차이점이 있습니다.

  • solid-query primitive(예: useQuery, useMutation, useIsFetching)의 인수는 함수이므로 반응형 범위에서 추적할 수 있습니다.
// ❌ react version
useQuery({
queryKey: ['todos', todo],
queryFn: fetchTodos,
})

// ✅ solid version
useQuery(() => ({
queryKey: ['todos', todo],
queryFn: fetchTodos,
}))
  • <Suspense> boundary 내부에서 쿼리 데이터에 접근하면 별도 설정 없이 쿼리에 Suspense가 작동합니다.
import { For, Suspense } from 'solid-js'

function Example() {
const query = useQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodos,
}))
return (
<div>
{/* ✅ Will trigger loading fallback, data accessed in a suspense boundary. */}
<Suspense fallback={'Loading...'}>
<For each={query.data}>{(todo) => <div>{todo.title}</div>}</For>
</Suspense>
{/* ❌ Will not trigger loading fallback, data not accessed in a suspense boundary. */}
<For each={query.data}>{(todo) => <div>{todo.title}</div>}</For>
</div>
)
}
  • Solid Query 프리미티브는 구조 분해를 지원하지 않습니다. 이러한 함수의 반환 값은 store이며, 그 속성은 반응형 컨텍스트에서만 추적됩니다.
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/solid-query'
import { Match, Switch } from 'solid-js'

const queryClient = new QueryClient()

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}

function Example() {
// ❌ react version -- supports destructing outside reactive context
// const { isPending, error, data } = useQuery({
// queryKey: ['repoData'],
// queryFn: () =>
// fetch('https://api.github.com/repos/tannerlinsley/react-query').then(
// (res) => res.json()
// ),
// })

// ✅ solid version -- does not support destructuring outside reactive context
const query = useQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(
(res) => res.json(),
),
}))

// ✅ access query properties in JSX reactive context
return (
<Switch>
<Match when={query.isPending}>Loading...</Match>
<Match when={query.isError}>Error: {query.error.message}</Match>
<Match when={query.isSuccess}>
<div>
<h1>{query.data.name}</h1>
<p>{query.data.description}</p>
<strong>👀 {query.data.subscribers_count}</strong>{' '}
<strong>{query.data.stargazers_count}</strong>{' '}
<strong>🍴 {query.data.forks_count}</strong>
</div>
</Match>
</Switch>
)
}
  • Signal 및 store 값은 함수 인수에 직접 전달할 수 있습니다. Solid Query는 쿼리 store를 자동으로 업데이트합니다.
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/solid-query'
import { createSignal, For } from 'solid-js'

const queryClient = new QueryClient()

function Example() {
const [enabled, setEnabled] = createSignal(false)
const [todo, setTodo] = createSignal(0)

// ✅ passing a signal directly is safe and observers update
// automatically when the value of a signal changes
const todosQuery = useQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodos,
enabled: enabled(),
}))

const todoDetailsQuery = useQuery(() => ({
queryKey: ['todo', todo()],
queryFn: fetchTodo,
enabled: todo() > 0,
}))

return (
<div>
<Switch>
<Match when={todosQuery.isPending}>
<p>Loading...</p>
</Match>
<Match when={todosQuery.isError}>
<p>Error: {todosQuery.error.message}</p>
</Match>
<Match when={todosQuery.isSuccess}>
<For each={todosQuery.data}>
{(todo) => (
<button onClick={() => setTodo(todo.id)}>{todo.title}</button>
)}
</For>
</Match>
</Switch>
<button onClick={() => setEnabled(!enabled())}>Toggle enabled</button>
</div>
)
}

function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
  • 오류는 SolidJS의 네이티브 ErrorBoundary 컴포넌트를 사용하여 포착하고 재설정할 수 있습니다. 오류가 ErrorBoundary로 발생하도록 하려면 throwOnError 또는 suspense 옵션을 true로 설정합니다.

  • 속성 추적은 Solid의 세밀한 반응성을 통해 처리되므로 notifyOnChangeProps와 같은 옵션은 필요하지 않습니다