Skip to main content
React Native Introduction
CHAPTER 18 Beginner

API Calls and Fetch Requests

Updated: May 16, 2026
7 min read

# CHAPTER 18

API Calls and Fetch Requests

1. Introduction

A mobile app without an internet connection is just a calculator. Modern applications rely on external servers to provide dynamic content: live weather updates, social media feeds, banking records, and e-commerce catalogs. To get this data, your app must communicate with a web server using an Application Programming Interface (API). In this chapter, we will master API Calls and Fetch Requests. We will utilize JavaScript's built-in fetch API, handle asynchronous network delays using async/await, manage UI loading states, and successfully execute GET and POST requests.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the lifecycle of an HTTP request.
  • Execute an HTTP GET request using the fetch API.
  • Parse server responses from raw Strings into JSON objects.
  • Manage isLoading and error states in the UI.
  • Execute an HTTP POST request to send data to a server.

3. The fetch API and Asynchronous Logic

When an app asks a server across the world for data, it might take 2 seconds to reply. If the app freezes for 2 seconds while waiting, the OS will crash it. We must use Asynchronous Programming (async/await) to tell React: *"Go fetch the data in the background, but let the user keep scrolling the app in the meantime."*

4. Executing a GET Request (Fetching Data)

A GET request is used to retrieve data (like a list of users). We will use the free JSONPlaceholder API for testing.
javascript
12345678910111213141516
// 1. Mark the function as async!
const fetchUsers = async () => {
  try {
    // 2. AWAIT the network request
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    
    // 3. The response is a raw string. We must parse it into JSON (JavaScript Objects)!
    const data = await response.json();
    
    // 4. Do something with the data
    console.log(data); 
  } catch (error) {
    // 5. Catch internet connection failures!
    console.error("Failed to fetch data:", error);
  }
};

5. Integrating APIs with React State and useEffect

You rarely want to press a button to load data. Usually, you want the data to fetch automatically the millisecond the screen opens! To do this, we put our fetch call inside a useEffect hook with an empty dependency array [] (meaning: run this exactly once when the component mounts).

We also need three pieces of State: The Data, the Loading indicator, and Error messages.

javascript
1234567891011121314151617181920212223242526272829303132333435363738394041424344
import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, ActivityIndicator } from 'react-native';

export default function UserListScreen() {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(true); // True by default!
  const [error, setError] = useState(null);

  // Runs instantly when the screen opens!
  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      if (!response.ok) throw new Error("Network response was not ok");
      
      const data = await response.json();
      setUsers(data); // Save data to state!
    } catch (err) {
      setError(err.message);
    } finally {
      setIsLoading(false); // Turn off the loading spinner!
    }
  };

  // UI RENDERING
  if (isLoading) {
    return <ActivityIndicator size="large" color="blue" style={{ flex: 1 }} />;
  }

  if (error) {
    return <Text style={{ color: &#039;red&#039;, textAlign: &#039;center&#039; }}>Error: {error}</Text>;
  }

  return (
    <FlatList
      data={users}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => <Text style={{ padding: 20 }}>{item.name}</Text>}
    />
  );
}

6. Executing a POST Request (Sending Data)

A POST request is used to create or send data (like logging in or submitting a form). To use POST, you must add an options object to the fetch call, specifying the method, headers, and the stringified body data!
javascript
123456789101112131415161718192021
const createPost = async (title, bodyText) => {
  try {
    const response = await fetch(&#039;https://jsonplaceholder.typicode.com/posts', {
      method: &#039;POST&#039;, // Change method from GET to POST
      headers: {
        &#039;Content-Type&#039;: &#039;application/json&#039;, // Tell the server we are sending JSON
      },
      // You cannot send a raw object over the internet. You MUST stringify it!
      body: JSON.stringify({
        title: title,
        body: bodyText,
        userId: 1,
      }),
    });

    const result = await response.json();
    console.log("Successfully created post ID:", result.id);
  } catch (error) {
    console.error("Error creating post:", error);
  }
};

7. Visual Learning: The API Lifecycle

txt
1234567891011
[ Screen Mounts ] -> useEffect fires
      |
[ State: isLoading = true ] -> UI draws Spinning Wheel
      |
[ fetch() sent to Server ]
      |
[ JSON Data arrives ]
      |
[ State: setUsers(data), setIsLoading(false) ]
      |
[ UI Re-Renders ] -> Spinning Wheel disappears, FlatList draws the data!

8. Common Mistakes

  • Forgetting response.json(): A common beginner error is doing const data = await fetch(url); and then trying to console.log(data.name). The fetch call returns a Response *Object* containing headers and status codes, not the actual JSON body. You MUST perform a second asynchronous step: await data.json() to parse the body text into usable JavaScript objects!

9. Best Practices

  • The finally Block: Notice in Section 5 we put setIsLoading(false) inside a finally block instead of at the end of the try block. The finally block executes *no matter what happens*. If the internet fails and the catch block runs, the loading spinner will still be turned off, ensuring the user isn't trapped staring at an infinite spinning wheel.

10. Practice Exercises

  1. 1. What built-in React hook is used to automatically trigger an API fetch call exactly once when a screen first opens?
  1. 2. What JavaScript function must be used to convert a JavaScript Object into a raw string before sending it inside the body of a POST request?

11. MCQs with Answers

Question 1

When making an HTTP POST request using the Fetch API, why is it mandatory to include 'Content-Type': 'application/json' in the headers?

Question 2

In a standard data-fetching component, what is the architectural purpose of implementing an isLoading boolean state variable?

12. Interview Questions

  • Q: Walk me through the complete lifecycle of a component fetching data on mount, focusing on the interplay between useEffect, fetch, and the sequential updates to isLoading and data states.
  • Q: Explain the necessity of the JSON.stringify() method when executing a POST request body, and its counterpart response.json() when receiving data. Why can't raw JavaScript objects traverse the network?
  • Q: Describe how you would gracefully handle a 500 Internal Server Error response from a fetch call, specifically regarding updating the UI to inform the user.

13. FAQs

Q: My fetch call works on iOS but fails on the Android Emulator when I try to connect to my local computer's Node.js server (http://localhost:3000). Why? A: localhost on the Android emulator points to the emulator itself, not your computer! You must replace localhost with the special Android alias 10.0.2.2 (e.g., http://10.0.2.2:3000) or use your computer's actual physical IP address.

14. Summary

In Chapter 18, our application connected to the world. We embraced Asynchronous Programming, utilizing async/await to process network delays without freezing the UI. We mastered the built-in fetch API, executing GET requests to retrieve external data and POST requests to send form data. We orchestrated the complex lifecycle of network requests using useEffect, ensuring users are greeted with professional ActivityIndicators while data loads securely into the application's state.

15. Next Chapter Recommendation

While fetch is great, it requires a lot of repetitive boilerplate code (like manually parsing JSON every time). The enterprise industry uses a more powerful library. Proceed to Chapter 19: Axios and API Integration.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·