Skip to main content

Recipes

Authentication & Refresh Tokens

Configure global authentication handling, including automatic token injection and seamless refresh flows on 401 errors.

import { createClient } from '@braine/quantum-query';

const client = createClient({
baseURL: 'https://api.example.com',
auth: {
// 1. Inject Token: Called before every request
getToken: async () => {
const token = localStorage.getItem('access_token');
return token; // Returns string or null
},

// 2. Refresh Logic: Called automatically on 401 response
onTokenExpired: async (client) => {
try {
const refreshToken = localStorage.getItem('refresh_token');
if (!refreshToken) return null;

// Perform refresh using a separate fetch or client instance
// to avoid infinite loops if the refresh endpoint also returns 401
const response = await fetch('https://api.example.com/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken })
});

if (!response.ok) throw new Error('Refresh failed');

const data = await response.json();

// Save new tokens
localStorage.setItem('access_token', data.accessToken);
localStorage.setItem('refresh_token', data.refreshToken);

return data.accessToken; // Return new token to retry original request
} catch (err) {
// Refresh failed - clean up and redirect
localStorage.clear();
window.location.href = '/login';
return null;
}
},

// 3. Auth Failed: Called if onTokenExpired returns null or fails
onAuthFailed: () => {
window.location.href = '/login';
}
}
});

Optimistic Updates

Update the UI immediately before the network request finishes.

const { refetch } = useQuery({ queryKey: ['todos'], ... });

const handleAddTodo = async (newTodo) => {
// 1. Snapshot previous state (optional) or just write
queryCache.set(['todos'], (old) => [...old, newTodo]);

// 2. Perform mutation
await api.post('/todos', newTodo);

// 3. Revalidate to ensure server consistency
queryCache.invalidate(['todos']);
};

Infinite Scroll UI

Simple implemention with a "Load More" button.

function PostList() {
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam }) => fetchPosts(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor
});

if (!data) return <Skeleton />;

return (
<div>
{data.pages.map(page => (
page.items.map(post => <Post key={post.id} data={post} />)
))}
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage}
>
{hasNextPage ? 'Load More' : 'No More Data'}
</button>
</div>
);
}