@forgedevstack/forge-query
v1.0.0
Published
Powerful data fetching and caching library for React with DevTools support
Maintainers
Readme
Forge Query
Why Forge Query?
| Feature | Forge Query | Others | |---------|-------------|--------| | Bundle Size | ~12KB | 30KB+ | | DevTools | Built-in + Chrome Extension | Separate package | | Setup | 2 lines | 10+ lines | | Learning Curve | Minimal | Steep | | TypeScript | First-class | Added later |
Features
- Simple API — Just
useQueryanduseMutation - Smart Caching — Automatic with configurable stale/cache times
- Background Sync — Auto-refetch on focus, reconnect, and intervals
- Optimistic Updates — Instant UI feedback
- DevTools — In-app panel + Chrome extension
- Tiny — ~12KB gzipped
- Flexible — Works with fetch, axios, graphql, or any async function
Quick Start
1. Install
npm install @forgedevstack/forge-query2. Setup
import { QueryClient, QueryClientContext } from '@forgedevstack/forge-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientContext.Provider value={queryClient}>
<YourApp />
</QueryClientContext.Provider>
);
}3. Fetch Data
import { useQuery } from '@forgedevstack/forge-query';
function UserProfile({ userId }) {
const { data, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
});
if (isLoading) return <Spinner />;
if (error) return <Error message={error.message} />;
return <Profile user={data} />;
}4. Mutate Data
import { useMutation, useQueryClient } from '@forgedevstack/forge-query';
function CreateTodo() {
const queryClient = useQueryClient();
const { mutate, isLoading } = useMutation({
mutationFn: (todo) => fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(todo),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] });
},
});
return (
<button onClick={() => mutate({ title: 'New Todo' })} disabled={isLoading}>
Add Todo
</button>
);
}DevTools
In-App Panel
Add the DevTools component to see all queries, logs, and cache in real-time:
import { ForgeQueryDevTools } from '@forgedevstack/forge-query/devtools';
function App() {
return (
<QueryClientContext.Provider value={queryClient}>
<YourApp />
<ForgeQueryDevTools />
</QueryClientContext.Provider>
);
}Chrome Extension
Get a dedicated DevTools panel in Chrome:
- Download from Chrome Web Store (coming soon)
- Or build from source:
cd devtools-extension npm install npm run build - Load in Chrome: Extensions → Developer Mode → Load Unpacked
Features:
- View all queries and their status
- Activity logs with timestamps
- Cache statistics and data preview
- Refetch, invalidate, or remove queries
API Reference
useQuery
const {
data, // The fetched data
error, // Error if failed
isLoading, // Initial loading state
isFetching, // Any fetching (including background)
isError, // Error state
isSuccess, // Success state
refetch, // Manual refetch function
} = useQuery({
queryKey: ['users'], // Unique cache key
queryFn: fetchUsers, // Async function
staleTime: 60000, // Time until stale (ms)
cacheTime: 300000, // Cache retention (ms)
retry: 3, // Retry attempts
enabled: true, // Enable/disable
refetchOnMount: true, // Refetch on mount
refetchOnWindowFocus: true, // Refetch on focus
refetchInterval: false, // Auto-refetch interval
});useMutation
const {
mutate, // Trigger mutation
mutateAsync, // Returns promise
data, // Result data
error, // Error if failed
isLoading, // Loading state
reset, // Reset state
} = useMutation({
mutationFn: (data) => createItem(data),
onMutate: (variables) => { /* Before mutation */ },
onSuccess: (data) => { /* On success */ },
onError: (error) => { /* On error */ },
onSettled: () => { /* Always runs */ },
});QueryClient
const queryClient = new QueryClient({
defaultOptions: {
staleTime: 0,
cacheTime: 5 * 60 * 1000,
retry: 3,
},
});
// Methods
queryClient.getQueryData(['users']); // Get cached data
queryClient.setQueryData(['users'], newData); // Set cache
queryClient.invalidateQueries(['users']); // Mark stale & refetch
queryClient.refetchQueries(['users']); // Force refetch
queryClient.removeQueries(['users']); // Remove from cache
queryClient.clear(); // Clear allExamples
Dependent Queries
const { data: user } = useQuery({
queryKey: ['user', userId],
queryFn: fetchUser,
});
const { data: posts } = useQuery({
queryKey: ['posts', user?.id],
queryFn: () => fetchPosts(user.id),
enabled: !!user, // Wait for user
});Optimistic Updates
const { mutate } = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
await queryClient.cancelQueries(['todos']);
const previous = queryClient.getQueryData(['todos']);
queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);
return { previous };
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previous);
},
});With TypeScript
interface User {
id: number;
name: string;
}
const { data } = useQuery<User, Error>({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
});
// data is User | undefinedConfiguration
const queryClient = new QueryClient({
defaultOptions: {
staleTime: 0, // Data is stale immediately
cacheTime: 5 * 60 * 1000, // 5 minutes
retry: 3,
retryDelay: 1000,
refetchOnMount: true,
refetchOnWindowFocus: true,
refetchOnReconnect: true,
},
devtools: {
enabled: process.env.NODE_ENV === 'development',
maxLogs: 100,
},
});Browser Support
| Browser | Version | |---------|---------| | Chrome | 90+ | | Firefox | 90+ | | Safari | 14+ | | Edge | 90+ |
Contributing
We welcome contributions! See CONTRIBUTING.md.
License
MIT © ForgeDevStack
