React Data Fetching & Caching
Learn how a React application requests data from a server, waits for the response, handles loading/error/success states, and stores small browser-side values using localStorage for caching.
1. The Big Picture
Imagine your React application is a student. The student asks the server: “Give me student data.” The server takes some time and sends the answer.
fetch()JSON data
2. Promise States
A Promise represents a result that will arrive later.
const promise = new Promise((resolve, reject) => {
console.log("Pending...");
setTimeout(() => {
let success = true;
if (success) {
resolve("Student data received");
} else {
reject("Server error");
}
}, 2000);
});
promise
.then(data => console.log(data))
.catch(error => console.log(error));Try it: Promise simulator
3. Fetch API
fetch() is a Web API that initiates an asynchronous HTTP request and returns a Promise<Response>.
Step 1
fetch(url) starts an HTTP request.
Step 2
It returns immediately with a Promise.
Step 3
The Promise eventually settles with a Response object.
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error));fetch()response.json()fetch() gives a Response object, not the JSON data directly.4. Why response.json()?
The JSON body is not returned directly by fetch(). You use response.json() to read and parse the JSON body.
const response = await fetch(url); const data = await response.json(); console.log(data);
Response → JSON simulator
5. async/await
async/await is another way to write Promise-based code. The notes describe await as waiting for the Promise inside the current async function without blocking the browser's main thread.
Promise style
fetch(url) .then(response => response.json()) .then(data => console.log(data));
async/await style
async function getData() {
const response = await fetch(url);
const data = await response.json();
console.log(data);
}await means “wait for this Promise to finish” inside the async function; it does not block the entire browser.Error handling
try {
// request
}
catch(error) {
// error
}6. What is a Response?
The response variable is a Response object, not the actual JSON object.
const response = await fetch(url); response.status response.ok response.headers response.body
response.status
HTTP status information.
response.ok
True for successful HTTP status responses such as 200.
response.headers
Response header information.
response.body
Response body stream.
response.ok before treating the response as successful data.7. Complete React Fetching Example
The source combines useEffect, fetch, async/await, response.ok, JSON parsing, loading, success, and error handling.
import { useEffect, useState } from "react";
function App() {
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
async function getPost() {
try {
const response =
await fetch("https://jsonplaceholder.typicode.com/posts/1");
if (!response.ok) {
throw new Error("Failed to fetch data");
}
const data = await response.json();
setPost(data);
}
catch (error) {
setError(error.message);
}
finally {
setLoading(false);
}
}
getPost();
}, []);
if (loading) return <h2>Loading...</h2>;
if (error) return <h2>Error: {error}</h2>;
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
);
}
export default App;Interactive fetch workflow
8. Why useEffect()?
The notes explain that useEffect() is used when we want to perform work after the component appears.
Component loads
React renders the component first.
useEffect()
Runs the extra work after rendering.
fetch()
The API request starts.
setState
The received data is stored and React re-renders.
9. Loading, Error, Empty and Success
The API request can have different outcomes. The notes identify loading, error, success and also mention an empty-data case.
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [data, setData] = useState(null);
if (loading)
return <p>Loading...</p>;
if (error)
return <p>Error: {error}</p>;
return <p>{data.title}</p>;Try the four UI states
10. What is Caching?
Imagine you downloaded a book yesterday. Would you download the same book again every time you want to read it? No. You keep a copy.
Without cache
With cache
Interactive cache decision
11. localStorage
The source identifies localStorage as a Web Storage API that stores key-value pairs in the browser.
- Data remains after page refresh.
- It can remain after reopening the browser for the same origin.
- It is useful for small browser-side cached values.
// Store
localStorage.setItem("name", "Avinash");
// Read
const name = localStorage.getItem("name");
// Remove
localStorage.removeItem("name");
// Clear everything
localStorage.clear();Try browser localStorage
12. Caching Objects
localStorage stores strings. To store an object, convert it with JSON.stringify(), and use JSON.parse() when retrieving it.
const student = {
name: "Ravi",
age: 20
};
localStorage.setItem(
"student",
JSON.stringify(student)
);
const student =
JSON.parse(localStorage.getItem("student"));JSON.stringify()JSON.parse()Try object caching
13. Real Cache Timestamp
For a real cache, the source says to also store the time the data was saved.
{
savedAt: Date.now(),
data: posts
}Interactive cache record
14. Complete React Data-Fetching Workflow
fetch()gets data from an API.async/awaitmakes Promise code easier to read.useEffect()is commonly used for fetching initial data.useState()stores fetched data and loading/error state.localStoragestores small browser-side data and can be used for caching.
Quick Reference
fetch(url)Starts an async HTTP request.response.json()Reads/parses the JSON body.response.okChecks successful HTTP status.async / awaitReadable Promise-based style.useEffect()Runs side-effect work after rendering.useState()Stores fetched data/loading/error state.localStorageStores small browser-side key-value data.JSON.stringify()JavaScript object → JSON string.JSON.parse()JSON string → JavaScript value.15. Quick Check
fetch() return?
response.json() needed?