@skyjt/query-solid
v0.1.4
Published
SolidJS query utilities and provider.
Readme
@skyjt/query-solid
A declarative, highly-efficient data-fetching and caching library for SolidJS, featuring request deduplication, cache lifecycle management, automatic invalidation, and server-side rendering (SSR) hydration support.
Features
- Reactive Queries: Automatically refetches data when reactive query keys (signals or functions) change.
- Request Deduplication: Reuses in-flight promises to prevent duplicate simultaneous network requests.
- Cache Lifecycle (Garbage Collection): Automatically garbage-collects unused cache entries after a configurable
gcTime. - Stale-While-Revalidate: Keeps track of data freshness with
staleTime, serving cached data instantly and background-fetching only when stale. - Declarative Mutations: Perform side effects (POST/PUT/DELETE) and easily track status (
isPending,isSuccess,isError) with success/error callbacks. - Cache Invalidation: Force-refetch queries on-demand using
client.invalidateQueries(key). - SSR Hydration: Automatically serializes cache state on the server using
serovaland hydrates it on the client without duplicate fetches.
Install
npm install @skyjt/query-solid
# or
bun add @skyjt/query-solidUsage
1. Setup Provider
Initialize a QueryClient and wrap your application in the <QueriesProvider>.
import { QueriesProvider, QueryClient } from "@skyjt/query-solid";
const queryClient = new QueryClient({
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 10, // 10 minutes
});
function App() {
return (
<QueriesProvider client={queryClient}>
<MyComponent />
</QueriesProvider>
);
}2. Basic Query
Use useSolidQuery to request and cache asynchronous data.
import { useSolidQuery } from "@skyjt/query-solid";
function MyComponent() {
const query = useSolidQuery({
queryKey: () => ["todos"],
queryFn: async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/todos");
return res.json();
}
});
return (
<Show when={!query.isLoading} fallback={<p>Loading...</p>}>
<Show when={!query.isError} fallback={<p>Error: {String(query.error)}</p>}>
<ul>
<For each={query.data}>
{(todo) => <li>{todo.title}</li>}
</For>
</ul>
</Show>
</Show>
);
}3. Dynamic/Dependent Queries
Make queries depend on reactive state by passing a getter function to queryKey and utilizing the enabled option.
import { useSignal } from "@skyjt/signals-solid";
import { useSolidQuery } from "@skyjt/query-solid";
const todoId = useSignal(1);
const query = useSolidQuery({
// Automatically refetches whenever todoId changes
queryKey: () => ["todo", todoId.value],
queryFn: async () => {
const res = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`);
return res.json();
},
enabled: () => todoId.value > 0 // Only run if ID is valid
});4. Mutations and Invalidation
Modify server state using useSolidMutation and trigger refetching with invalidateQueries.
import { useSolidMutation, QueryClientContext } from "@skyjt/query-solid";
import { useContext } from "solid-js";
function AddTodo() {
const client = useContext(QueryClientContext)!;
const mutation = useSolidMutation({
mutationFn: async (newTodo: { title: string }) => {
return fetch("https://jsonplaceholder.typicode.com/todos", {
method: "POST",
body: JSON.stringify(newTodo),
}).then((res) => res.json());
},
onSuccess: () => {
// Invalidate cache to force list refetch
client.invalidateQueries(["todos"]);
}
});
return (
<button
disabled={mutation.isPending}
onClick={() => mutation.mutate({ title: "New Task" })}
>
{mutation.isPending ? "Adding..." : "Add Todo"}
</button>
);
}License
Apache-2.0
