뮤테이션
쿼리와 달리 뮤테이션은 서버 측 부수 효과를 생성, 업데이트, 삭제하거나 그 밖의 방식으로 수행하는 데 사용됩니다. Lit에서는 createMutationController를 사용합니다.
import { LitElement, html } from 'lit'
import {
QueryClient,
QueryClientProvider,
createMutationController,
createQueryController,
} from '@tanstack/lit-query'
const queryClient = new QueryClient()
class AppQueryProvider extends QueryClientProvider {
constructor() {
super()
this.client = queryClient
}
}
customElements.define('app-query-provider', AppQueryProvider)
class TodosView extends LitElement {
private readonly todos = createQueryController(this, {
queryKey: ['todos'],
queryFn: fetchTodos,
})
private readonly addTodo = createMutationController(this, {
mutationFn: createTodo,
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
render() {
const query = this.todos()
const mutation = this.addTodo()
const todos = query.data ?? []
return html`
${mutation.isError ? html`<p>${mutation.error.message}</p>` : null}
${mutation.isSuccess ? html`<p>Todo added</p>` : null}
<button
?disabled=${mutation.isPending}
@click=${() => this.addTodo.mutate({ title: 'Write mutation docs' })}
>
${mutation.isPending ? 'Adding...' : 'Add Todo'}
</button>
<ul>
${todos.map((todo) => html`<li>${todo.title}</li>`)}
</ul>
`
}
}
customElements.define('todos-view', TodosView)
컨트롤러가 Lit 컨텍스트에서 동일한 QueryClient를 이행할 수 있도록 provider 아래에서 요소를 렌더링합니다:
<app-query-provider>
<todos-view></todos-view>
</app-query-provider>
뮤테이션 상태
뮤테이션은 다음 주요 상태 중 하나일 수 있습니다:
isIdle또는status === 'idle': 실행된 뮤테이션이 없거나 뮤테이션이 재설정되었습니다isPending또는status === 'pending': 뮤테이션이 실행 중입니다isError또는status === 'error': 뮤테이션이 실패했으며error를 사용할 수 있습니다isSuccess또는status === 'success': 뮤테이션이 완료되었으며data를 사용할 수 있습니다
변수
mutate를 호출하여 뮤테이션 함수에 변수를 전달합니다:
this.addTodo.mutate({
title: this.nextTitle,
})
요소가 연결된 QueryClientProvider 아래에 있지 않고 명시적인 client도 전달되지 않은 경우처럼 controller가 QueryClient를 이행할 수 없으면 mutate는 동기적으로 오류를 발생시킵니다. mutateAsync는 동일한 설정 문제를 거부된 Promise로 보고합니다.
Promise가 필요할 때 mutateAsync를 사용합니다:
try {
const created = await this.addTodo.mutateAsync({ title: this.nextTitle })
this.nextTitle = created.title
} catch (error) {
this.errorMessage = String(error)
}
뮤테이션 상태 재설정
접근자에는 reset이 포함됩니다:
html`
${mutation.isError
? html`<button @click=${() => this.addTodo.reset()}>Clear error</button>`
: null}
`
부수 효과
뮤테이션 옵션은 onMutate, onError, onSuccess, onSettled를 지원합니다. 페이지네이션 예제는 명시적인 queryClient를 controller에 전달하고, 낙관적 업데이트와 롤백에 동일한 범위 내 client를 사용합니다:
private readonly favoriteMutation = createMutationController(
this,
{
mutationKey: ['toggle-project-favorite'],
mutationFn: async (input) => {
const response = await toggleProjectFavoriteOnServer(input)
return response.project
},
onMutate: async (variables) => {
await queryClient.cancelQueries({ queryKey: ['projects'] })
const snapshots = queryClient.getQueriesData<ProjectsPageResponse>({
queryKey: ['projects'],
})
for (const [key, existing] of snapshots) {
if (!existing) continue
queryClient.setQueryData<ProjectsPageResponse>(key, {
...existing,
projects: existing.projects.map((project) =>
project.id === variables.id
? { ...project, isFavorite: variables.isFavorite }
: project,
),
})
}
return { snapshots }
},
onError: (_error, _variables, context) => {
for (const [key, snapshot] of context?.snapshots ?? []) {
queryClient.setQueryData(key, snapshot)
}
},
onSettled: async () => {
await queryClient.invalidateQueries({ queryKey: ['projects'] })
},
},
queryClient,
)
정확히 실행 가능한 흐름은 페이지네이션 예제를 참조하세요.