Based on the uploaded “finalFetchingAndCaching” notes

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.

fetch()Promiseasync/await response.json()useEffectuseState localStorageJSON.stringify()JSON.parse()

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.

React Application
→
fetch()
Server
→
JSON data
React Application
Why is it asynchronous? The network may take time, so the React application should not freeze while waiting.

2. Promise States

A Promise represents a result that will arrive later.

PendingWaiting
FulfilledSuccess
RejectedFailed
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

Pending — click an outcome.

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()
→
Promise
→
response.json()
→
data
Important: 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

Response object
→
response.json()
→
JavaScript data
Waiting...

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);
}
Remember: 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.

Practical rule from the notes: Check 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

Ready to fetch.

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.

Component loads
→
useEffect()
→
fetch()
→
setState
→
UI
Key distinction: the API request is side-effect work outside the normal description of the UI.

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.

Loading“Loading...”
Error“Error: ...”
EmptyNo data to show
SuccessShow the data
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

Choose a state.

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.

Cache: keep a temporary copy so we do not repeatedly fetch the same data.

Without cache

React
→
Server
→
Data
React again
→
Server again
→
Same data again

With cache

React
→
Is cached data available?
YES
→
Use cache
NO
→
Server
→
Data
→
Save in cache

Interactive cache decision

Choose the cache situation.

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

No action yet.

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"));
Object
→
JSON.stringify()
→
String
→
localStorage
localStorage
→
String
→
JSON.parse()
→
Object

Try object caching

No cached object action yet.

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

No record created.

14. Complete React Data-Fetching Workflow

FETCH
→
localStorage
→
Promise
→
async/await
→
useEffect
→
API Request
Loading
→
Error / Success
→
setState
→
Re-render UI
Five things to remember from the source:
  1. fetch() gets data from an API.
  2. async/await makes Promise code easier to read.
  3. useEffect() is commonly used for fetching initial data.
  4. useState() stores fetched data and loading/error state.
  5. localStorage stores 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

1. Why is data fetching asynchronous?
2. What does fetch() return?
3. Why is response.json() needed?
4. Which property checks whether the HTTP response was successful?
5. Which Hook is commonly used for fetching initial data?
6. What does localStorage store?
7. Which pair is used for objects in localStorage?