Coordinate server data with QueryClient
Read and update one asynchronous todo source through shared query and mutation state.
The self-contained example reads an in-memory source, adds one item, invalidates the query after success, fetches the current list and renders both handle statuses.
Table of contents
Main APIs
- QueryClient
- Creates query and mutation handles over a shared cache with invalidation and persistence controls.
- QueryHandle
- Exposes the public state and operations of a query.
- MutationHandle
- Exposes the public state and operations of a mutation.
tsximport { mount } from "valyrian.js";
import { QueryClient } from "valyrian.js/query";
type Todo = { id: number; title: string };
const records: Todo[] = [{ id: 1, title: "Learn Valyrian.js" }];
let nextId = 2;
const client = new QueryClient({ staleTime: 30_000 });
const todos = client.query({
key: ["todos"],
fetcher: async (): Promise<Todo[]> => records.map((todo) => ({ ...todo })),
});
const addTodo = client.mutation<{ title: string }, Todo>({
execute: async (todo) => {
const created = { id: nextId, title: todo.title };
nextId += 1;
records.push(created);
return { ...created };
},
onSuccess: () => todos.invalidate(),
});
await todos.fetch();
await addTodo.execute({ title: "Learn Valyrian.js" });
await todos.fetch();
let cacheStatus = `cached todos: ${todos.state.data?.length ?? 0}`;
function QueryStatus() {
return (
<main>
<p>
query: {todos.state.status}; mutation: {addTodo.state.status}
</p>
<p>{cacheStatus}</p>
<button
type="button"
onclick={() => {
client.clear();
cacheStatus = "cache cleared";
}}
>
Clear query cache
</button>
</main>
);
}
mount("body", QueryStatus);Error
Query and mutation handles expose separate error states.