Rules Hub

Coding Rules Library

← Back to all rules
fullstack ruleStack: react
react-querydata-fetchingcachingperformancearchitecture

Integrate QueryClient in fetch utilities

Pass QueryClient and query keys to fetch utilities to enable caching and deduplication instead of raw fetching.

PR: Feat/FCK-2245 - Cache Bellsheep and profile loaders with TanStack Query #343Created: Dec 10, 2025

Bad example

Old codets
1export async function fetchUser(id: string, signal?: AbortSignal) {
2 // Always hits the network, ignoring potential cache
3 const res = await fetch(`/api/users/${id}`, { signal });
4 if (!res.ok) throw new Error('Failed to fetch');
5 return res.json();
6}
7
8// Usage in a loader
9export const loader = async ({ request, params }: LoaderFunctionArgs) => {
10 return fetchUser(params.id, request.signal);
11};

Explanation (EN)

The fetch function blindly executes a network request every time it is called. It fails to utilize any caching layer, leading to redundant data fetching and slower user experiences when navigating between known states.

Objašnjenje (HR)

Funkcija za dohvaćanje slijepo izvršava mrežni zahtjev svaki put kad se pozove. Ne koristi nikakav sloj za predmemoriranje (caching), što dovodi do nepotrebnog dohvaćanja podataka i sporijeg korisničkog iskustva pri navigaciji.

Good example

New codets
1import { QueryClient, QueryKey } from '@tanstack/react-query';
2
3interface FetchOptions {
4 queryClient?: QueryClient;
5 queryKey?: QueryKey;
6 signal?: AbortSignal;
7}
8
9export async function fetchUser(id: string, options: FetchOptions = {}) {
10 const { queryClient, queryKey, signal } = options;
11 const fetchFn = async () => {
12 const res = await fetch(`/api/users/${id}`, { signal });
13 if (!res.ok) throw new Error('Failed to fetch');
14 return res.json();
15 };
16
17 // If client and key are present, try cache first or deduplicate request
18 if (queryClient && queryKey) {
19 return queryClient.ensureQueryData({
20 queryKey,
21 queryFn: fetchFn,
22 });
23 }
24
25 return fetchFn();
26}
27
28// Usage in a loader
29export const loader = async ({ request, params, context }: LoaderFunctionArgs) => {
30 const queryClient = context.get(queryClientContext);
31 return fetchUser(params.id, {
32 queryClient,
33 queryKey: ['user', params.id],
34 signal: request.signal,
35 });
36};

Explanation (EN)

The fetch utility now accepts a `QueryClient` and `queryKey`. This allows it to use `ensureQueryData` to return cached data immediately if available, or fetch and cache the result for future use, significantly improving performance.

Objašnjenje (HR)

Funkcija za dohvaćanje sada prihvaća `QueryClient` i `queryKey`. To joj omogućuje korištenje `ensureQueryData` za trenutno vraćanje predmemoriranih podataka ako postoje ili dohvaćanje i spremanje rezultata za buduću upotrebu.