본문으로 건너뛰기

TanStack DB Solid 어댑터

설치​

npm install @tanstack/solid-db

Solid 프리미티브​

어댑터에서 사용할 수 있는 전체 프리미티브 목록은 Solid Functions Reference를 참조할 수 있습니다.

쿼리 작성(필터링, 조인, 집계 등)에 대한 종합적인 문서는 Live Queries Guide를 참조할 수 있습니다.

기본 사용법​

useLiveQuery​

useLiveQuery 프리미티브는 데이터가 변경될 때 컴포넌트를 자동으로 업데이트하는 라이브 쿼리를 생성합니다. 이 프리미티브는 data가 일반 배열이고 상태 필드(예: isLoading(), status())가 접근자인 객체를 반환합니다:

import { useLiveQuery } from '@tanstack/solid-db'
import { eq } from '@tanstack/db'
import { Show, For } from 'solid-js'

function TodoList() {
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => eq(todos.completed, false))
.select(({ todos }) => ({ id: todos.id, text: todos.text }))
)

return (
<Show when={!query.isLoading()} fallback={<div>Loading...</div>}>
<ul>
<For each={query.data}>
{(todo) => <li>{todo.text}</li>}
</For>
</ul>
</Show>
)
}

참고: query.data는 함수가 아니라 배열을 직접 반환하지만, isLoading(), status() 등의 상태 필드는 접근자 함수입니다.

시그널을 사용한 반응형 쿼리​

Solid는 세분화된 반응성을 사용하므로 쿼리가 시그널 변경을 자동으로 추적하고 이에 응답합니다. 쿼리 함수 내부에서 시그널을 호출하기만 하면 Solid가 시그널 변경 시 자동으로 다시 계산합니다:

import { createSignal } from 'solid-js'
import { useLiveQuery } from '@tanstack/solid-db'
import { gt } from '@tanstack/db'

function FilteredTodos(props: { minPriority: number }) {
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => gt(todos.priority, props.minPriority))
)

return <div>{query.data.length} high-priority todos</div>
}

props.minPriority가 변경되면 Solid의 반응성 시스템이 자동으로 다음을 수행합니다:

  1. 쿼리 함수 내부의 prop 액세스를 감지합니다
  2. 이전 라이브 쿼리 컬렉션을 정리합니다
  3. 업데이트된 값을 사용하여 새 쿼리를 생성합니다
  4. 새 데이터로 컴포넌트를 업데이트합니다

컴포넌트 상태의 시그널 사용​

import { createSignal } from 'solid-js'
import { useLiveQuery } from '@tanstack/solid-db'
import { eq, and } from '@tanstack/db'

function TodoList() {
const [userId, setUserId] = createSignal(1)
const [status, setStatus] = createSignal('active')

// Solid automatically tracks userId() and status() calls
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => and(
eq(todos.userId, userId()),
eq(todos.status, status())
))
)

return (
<div>
<select onChange={(e) => setStatus(e.currentTarget.value)}>
<option value="active">Active</option>
<option value="completed">Completed</option>
</select>
<div>{query.data.length} todos</div>
</div>
)
}

핵심 사항: React와 달리 의존성 배열이 필요하지 않습니다. Solid의 반응형 시스템은 쿼리 실행 중 액세스된 모든 시그널, prop 또는 스토어를 자동으로 추적합니다.

모범 사례​

쿼리 함수 내부에서 시그널에 액세스합니다:

import { createSignal } from 'solid-js'
import { useLiveQuery } from '@tanstack/solid-db'
import { gt } from '@tanstack/db'

function TodoList() {
const [minPriority, setMinPriority] = createSignal(5)

// Good - signal accessed inside query function
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => gt(todos.priority, minPriority()))
)

// Solid automatically tracks minPriority() and recomputes when it changes
return <div>{query.data.length} todos</div>
}

쿼리 함수 외부에서 시그널을 읽면 안 됩니다:

import { createSignal } from 'solid-js'
import { useLiveQuery } from '@tanstack/solid-db'
import { gt } from '@tanstack/db'

function TodoList() {
const [minPriority, setMinPriority] = createSignal(5)

// Bad - reading signal outside query function
const currentPriority = minPriority()
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => gt(todos.priority, currentPriority))
)
// Won't update when minPriority changes!

return <div>{query.data.length} todos</div>
}

정적 쿼리는 특별히 처리할 필요가 없습니다:

import { useLiveQuery } from '@tanstack/solid-db'

function AllTodos() {
// No signals accessed - query never changes
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
)

return <div>{query.data.length} todos</div>
}

미리 생성된 컬렉션 사용​

기존 컬렉션을 useLiveQuery에 전달할 수도 있습니다. 이는 여러 컴포넌트에서 쿼리를 공유할 때 유용합니다:

import { createLiveQueryCollection } from '@tanstack/db'
import { useLiveQuery } from '@tanstack/solid-db'

// Create collection outside component
const todosQuery = createLiveQueryCollection((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => eq(todos.active, true))
)

function TodoList() {
// Pass existing collection
const query = useLiveQuery(() => todosQuery)

return <div>{query.data.length} todos</div>
}