
Security News
Feross on the 10 Minutes or Less Podcast: Nobody Reads the Code
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.
@forgedevstack/forge-query
Advanced tools
Powerful data fetching and caching library for React with DevTools support
Powerful data fetching and caching library for React
| 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 |
useQuery and useMutationnpm install @forgedevstack/forge-query
import { QueryClient, QueryClientContext } from '@forgedevstack/forge-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientContext.Provider value={queryClient}>
<YourApp />
</QueryClientContext.Provider>
);
}
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} />;
}
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>
);
}
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>
);
}
Get a dedicated DevTools panel in Chrome:
cd devtools-extension
npm install
npm run build
Features:
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
});
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 */ },
});
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 all
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
});
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);
},
});
interface User {
id: number;
name: string;
}
const { data } = useQuery<User, Error>({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
});
// data is User | undefined
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 | Version |
|---|---|
| Chrome | 90+ |
| Firefox | 90+ |
| Safari | 14+ |
| Edge | 90+ |
We welcome contributions! See CONTRIBUTING.md.
MIT © ForgeDevStack
Part of the ForgeDevStack ecosystem
FAQs
Powerful data fetching and caching library for React with DevTools support
We found that @forgedevstack/forge-query demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.

Research
/Security News
Campaign of 108 extensions harvests identities, steals sessions, and adds backdoors to browsers, all tied to the same C2 infrastructure.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.