logo
Back to blogs

Optimizing Data Fetching in React using React.use

Mar 10, 2023 - 5 min read

Optimizing Data Fetching in React using React.use

Optimizing Data Fetching in React: Using Custom Caching to Prevent Unnecessary Requests

When working with React component, managing data fetching efficiently is crucial to providing a smooth and responsive user experience. In many cases using React.use or React.useEffect for fetching data can lead to multiple redundant requests, impacting both performance and resource usage. In this post, we’ll explore how to implement a custom caching mechanism to prevent unnecessary fetches while using React.Suspense and React.ErrorBoundary to handle loading states and errors.

The Problem: Redundant Fetches in React

Fetching data directly within a component can cause the same API endpoint to be called multiple times, especially when:

  • The component is re-rendered multiple times
  • The component is unmounted and re-mounted

Using React.use or similar hooks without caching results in repeated network requests, which not only slows down the application but also increases server load.

The Solution: A Custom Cache for Promises

A caching system can store and reuse promises to prevent redundant fetches. Below is an example of a simple caching class and how it integrates into a React component.

cache.tsx
1interface User { 2 id: number; 3 name: string; 4 username: string; 5 email: string; 6 phone: string; 7 website: string; 8} 9 10class Cache<T> { 11 private cache = new Map<string, Promise<T>>(); 12 13 async fetch(key: string, fetcher: () => Promise<T>): Promise<T> { 14 if (!this.cache.has(key)) { 15 try { 16 this.cache.set(key, fetcher()); 17 } catch (error) { 18 this.cache.delete(key); 19 throw error; 20 } 21 } 22 return this.cache.get(key)!; 23 } 24 25 clear() { 26 this.cache.clear(); 27 } 28} 29

This Cache<T> class stores promises in a map. It ensures that:

  • A promise is created only once per key.
  • Subsequent fetches return the same promise until it resolves or rejects.

Using the Cache in a React Component

user-profile.tsx
1export interface User { 2 id: number; 3 name: string; 4 username: string; 5 email: string; 6 phone: string; 7 website: string; 8} 9 10const userCache = new Cache<User>(); 11export function UserProfile({ username }: { username: string }) { 12 // Use the cache to fetch the user data and store it for preventing unnecessary fetches 13 const user = use(userCache.fetch(username, () => fetchUser(username))); 14 return ( 15 <div className="p-4 bg-white rounded-lg shadow-md"> 16 <h2 className="text-2xl font-bold mb-4">{user.name}</h2> 17 <div className="space-y-2"> 18 <p> 19 <span className="font-semibold">Username:</span> {user.username} 20 </p> 21 <p> 22 <span className="font-semibold">Email:</span> {user.email} 23 </p> 24 <p> 25 <span className="font-semibold">Phone:</span> {user.phone} 26 </p> 27 <p> 28 <span className="font-semibold">Website:</span> {user.website} 29 </p> 30 </div> 31 </div> 32 ); 33}