Caching Data to Optimize API Calls in React JS
In React applications, optimizing API calls by caching data can significantly improve performance and reduce unnecessary network requests. This article explains caching concepts and demonstrates examples of implementing caching in React.
Why Cache Data?
- Reduce the number of API calls, lowering server load and response times.
- Enhance user experience by avoiding repeated loading states for the same data.
- Improve performance by storing frequently accessed data locally.
Example 1: Simple In-Memory Caching
Below is an example of caching data in a React application using in-memory storage:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const cache = {};
function InMemoryCache() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = async () => {
const url = 'https://jsonplaceholder.typicode.com/posts/1';
if (cache[url]) {
setData(cache[url]);
setLoading(false);
} else {
try {
const response = await axios.get(url);
cache[url] = response.data; // Cache the response
setData(response.data);
} catch (err) {
console.error('Error fetching data:', err);
setError('Failed to fetch data. Please try again later.');
} finally {
setLoading(false);
}
}
};
useEffect(() => {
fetchData();
}, []);
return (
In-Memory Caching Example
{loading ? Loading...
: error ? {error}
: (
Title: {data.title}
Body: {data.body}
)}
);
}
export default InMemoryCache;
Example 2: Caching with Local Storage
Using the browser's localStorage
, we can persist cached data across page reloads:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function LocalStorageCache() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = async () => {
const url = 'https://jsonplaceholder.typicode.com/posts/1';
const cachedData = localStorage.getItem(url);
if (cachedData) {
setData(JSON.parse(cachedData));
setLoading(false);
} else {
try {
const response = await axios.get(url);
localStorage.setItem(url, JSON.stringify(response.data)); // Cache in localStorage
setData(response.data);
} catch (err) {
console.error('Error fetching data:', err);
setError('Failed to fetch data. Please try again later.');
} finally {
setLoading(false);
}
}
};
useEffect(() => {
fetchData();
}, []);
return (
Local Storage Caching Example
{loading ? Loading...
: error ? {error}
: (
Title: {data.title}
Body: {data.body}
)}
);
}
export default LocalStorageCache;
Example 3: Caching with React Query
React Query is a library that simplifies data fetching and caching. Here's an example:
import React from 'react';
import { useQuery } from 'react-query';
import axios from 'axios';
const fetchPost = async () => {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
return response.data;
};
function ReactQueryCache() {
const { data, error, isLoading } = useQuery('post-1', fetchPost, {
staleTime: 5000, // Cache the data for 5 seconds
cacheTime: 10000, // Keep unused data in cache for 10 seconds
});
return (
React Query Caching Example
{isLoading ? Loading...
: error ? Error fetching data
: (
Title: {data.title}
Body: {data.body}
)}
);
}
export default ReactQueryCache;
Best Practices
- Use caching libraries like React Query or SWR for robust caching mechanisms.
- Invalidate stale data after a specific time to ensure consistency.
- Persist cache data only when necessary to reduce storage overhead.
- Provide fallback mechanisms for expired or unavailable cached data.
By implementing caching techniques, you can optimize API calls and deliver a faster, smoother user experience in your React applications.