Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save brandonbryant12/50809f6bba2953570f0258b6851b43e3 to your computer and use it in GitHub Desktop.
Save brandonbryant12/50809f6bba2953570f0258b6851b43e3 to your computer and use it in GitHub Desktop.
### prefer tanstackquery over react query
We use **TanStack Query (TQ)** for all new Backstage front-end work and phase out legacy React Query code.
**Why TanStack Query?**
* Framework-agnostic core (future-proof if we add non-React widgets)
* Smaller, tree-shakable bundles → faster load times
* Smarter cache & request de-duplication
* First-class Suspense / SSR helpers
* One DevTools panel that works everywhere
---
#### Reading data (query)
```tsx
import { useQuery } from '@tanstack/react-query';
function TodoCount() {
const { data: todos = [], isLoading, isError } = useQuery({
queryKey: ['todos'],
queryFn : () => fetch('/api/todos').then(r => r.json()),
staleTime: 30_000, // fresh for 30 s
});
if (isLoading) return <>Loading…</>;
if (isError) return <>Error!</>;
return <>Total todos: {todos.length}</>;
}
### prefer tanstack query for front-end data fetching
TanStack Query (TQ) is our **standard** way to fetch and cache data in Backstage plugins.
While React Query v3 still works, all **new code must use TQ** and we will gradually migrate legacy files.
---
#### Why TanStack Query?
| Benefit | What it means for us |
|---------|---------------------|
| **Framework-agnostic core** | Same query cache even if we embed non-React UI in the future. |
| **Smaller, tree-shakable bundles** | ~10-15 % smaller JS payloads → faster Backstage load times. |
| **Automatic request de-duplication** | Multiple widgets that need the same data share **one** network call. |
| **Suspense & SSR helpers** | Cleaner `<Suspense>` boundaries and easier server-side rendering. |
| **Unified DevTools** | One debug panel (`@tanstack/react-query-devtools`) that works everywhere. |
---
#### Read data (query)
```tsx
import { useQuery } from '@tanstack/react-query';
export function TodoCount() {
const { data: todos = [], isLoading, isError } = useQuery({
queryKey: ['todos'],
queryFn : () => fetch('/api/todos').then(r => r.json()),
staleTime: 30_000, // treat data as “fresh” for 30 s
});
if (isLoading) return <>Loading…</>;
if (isError) return <>Error!</>;
return <>Total todos: {todos.length}</>;
}
Guidelines
• Always use an array for queryKey (['todos'], ['catalog', id]…).
• Prefer staleTime over polling; it avoids needless refetches.
• Gate the fetch with enabled: flag when data depends on something else.
Write data (mutation)
import { useMutation, useQueryClient } from '@tanstack/react-query';
export function AddTodoButton() {
const qc = useQueryClient();
const addTodo = useMutation({
mutationFn: (text: string) =>
fetch('/api/todos', { method: 'POST', body: JSON.stringify({ text }) }),
onSuccess: () => qc.invalidateQueries({ queryKey: ['todos'] }),
});
return (
<button onClick={() => addTodo.mutate('Buy milk')}>
Add “Buy milk”
</button>
);
}
Use invalidateQueries (or setQueryData for optimistic updates) so every component watching ['todos'] refreshes automatically.
DevTools (development only)
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
{process.env.NODE_ENV === 'development' && (
<ReactQueryDevtools position="right" />
)}
Toggle with Alt + D.
Migration tip
Replace old imports only—most code stays unchanged.
-import { useQuery } from 'react-query';
+import { useQuery } from '@tanstack/react-query';
Refactor files as you touch them; all new components must start with TanStack Query.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment