Hooks
React Hooks
React hooks for data fetching with full type safety
The @spoosh/react package provides React hooks for data fetching with full type safety.
Installation
npm install @spoosh/core @spoosh/reactSetup
import { Spoosh } from "@spoosh/core";
import { create } from "@spoosh/react";
import { cachePlugin } from "@spoosh/plugin-cache";
import { invalidationPlugin } from "@spoosh/plugin-invalidation";
import { deduplicationPlugin } from "@spoosh/plugin-deduplication";
const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
cachePlugin({ staleTime: 5000 }),
invalidationPlugin(),
deduplicationPlugin({ read: "in-flight" }),
]);
export const { useRead, useWrite, usePages, useQueue } = create(spoosh);Automatic Tag Generation
Spoosh automatically generates a cache tag from the resolved API path.
// api("users").GET() → tag: "users"
// api("users/:id").GET({ params: { id: 1 } }) → tag: "users/1"
// api("posts/:postId/comments").GET({ params: { postId: 5 } }) → tag: "posts/5/comments"Custom Tags
Override the auto-generated tag with custom tags:
// Single custom tag
const { data } = useRead((api) => api("users").GET(), {
tags: "my-users",
});
// Multiple custom tags
const { data } = useRead((api) => api("users").GET(), {
tags: ["users", "dashboard"],
});Cache Invalidation
The invalidationPlugin automatically refetches queries after mutations using wildcard pattern matching.
Pattern Matching
| Pattern | Matches |
|---|---|
"posts" | Exact match only |
"posts/*" | All children (posts/1, posts/1/comments) |
["posts", "posts/*"] | posts AND all children (default) |
const { trigger } = useWrite((api) => api("posts").POST());
// Default behavior — invalidates ["posts", "posts/*"]
await trigger({ body: { title: "New Post" } });
// Specific patterns
await trigger({
body: { title: "New Post" },
invalidate: ["posts", "posts/*"],
});
// Disable invalidation
await trigger({
body: { title: "New Post" },
invalidate: false,
});Manual Invalidation
Target specific patterns to invalidate:
const { trigger } = useWrite((api) => api("posts").POST());
await trigger({
body: { title: "New Post" },
invalidate: ["posts", "users/*", "dashboard"],
});Request Deduplication
The deduplicationPlugin prevents duplicate network requests when the same query is called multiple times simultaneously.
Deduplication Modes
| Mode | Description |
|---|---|
"in-flight" | Reuse pending request if same query is in progress (default for reads) |
false | Disable deduplication |
const { data } = useRead((api) => api("users").GET(), { dedupe: "in-flight" });When multiple components call the same query simultaneously, only one network request is made:
function Header() {
const { data: user } = useRead((api) => api("me").GET());
return <div>{user?.name}</div>;
}
function Sidebar() {
const { data: user } = useRead((api) => api("me").GET());
return <nav>{user?.email}</nav>;
}