Paramclasses Academy - Blog

Tutorials Details

←
Post 21 of 39
→

How to Fetch REST API Data in React Native Using Fetch and Axios ?

How to Fetch REST API Data in React Native Using Fetch and Axios ?

November 5, 2026

1. Introduction

Modern mobile applications frequently communicate with remote servers to retrieve and submit information.

For example:

  • A shopping application retrieves products from a server.

  • A student management application retrieves student records.

  • A news application retrieves the latest articles.

  • A social media application retrieves posts and user profiles.

This communication is commonly performed through a REST API (Representational State Transfer Application Programming Interface).

In this tutorial, we will learn how to connect a React Native application to a REST API using two popular approaches:

  1. JavaScript Fetch API

  2. Axios HTTP Client

We will also learn how to display API data using FlatList and manage loading and error states.

2. What Is an API?

An API allows two software applications to communicate with each other.

Consider a Student Management Application:

  1. The mobile application sends a request to a server.

  2. The server processes the request.

  3. The server retrieves student information from its database.

  4. The server sends a response to the mobile application.

  5. The application displays the received information.

Example API URL:

https://jsonplaceholder.typicode.com/users

This endpoint returns sample user information in JSON format.

3. What Is a REST API?

REST API is an architectural approach for communication between applications over HTTP.

Common HTTP methods include:

  • GET: Retrieve data from a server.

  • POST: Create new data.

  • PUT: Replace existing data.

  • PATCH: Update selected fields.

  • DELETE: Delete data.

Example:

GET https://jsonplaceholder.typicode.com/users

This request retrieves a list of users.

4. What Is JSON?

JSON stands for JavaScript Object Notation.

It is a lightweight data format commonly used for transferring information between applications and servers.

Example JSON response:

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "leanne@example.com"
}

In React Native, we can convert a JSON response into JavaScript data and display it inside our application.

5. What Is Fetch API?

Fetch is a built-in JavaScript networking API supported by React Native.

It allows us to send HTTP requests without installing an additional HTTP client library.

Basic syntax:

fetch("https://jsonplaceholder.typicode.com/users")
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.log(error);
  });

Fetch uses Promises and supports async/await.

6. What Is Axios?

Axios is a third-party Promise-based HTTP client.

It provides a convenient interface for sending HTTP requests.

Some important features include:

  • Simple GET and POST requests.

  • Automatic JSON response transformation.

  • Request and response interceptors.

  • Request timeout configuration.

  • Convenient HTTP error handling.

  • Request cancellation support.

Install Axios:

npm install axios

Basic example:

import axios from "axios";

const response = await axios.get(
  "https://jsonplaceholder.typicode.com/users"
);

console.log(response.data);

Unlike Fetch, Axios automatically provides the response body through response.data.

7. Create a React Native Project

We will create a practical Student Data Application using Expo.

Open your terminal and execute:

npx create-expo-app@latest StudentApiApp --template blank

Open the project:

cd StudentApiApp

Open it in Visual Studio Code:

code .

Start the Expo development server:

npx expo start

You can run the application using Expo Go or an Android emulator.

8. Understand the Project Structure

Our basic project structure will look like this:

StudentApiApp/
│
├── App.js
├── package.json
├── node_modules/
└── assets/

We will write our main application code inside App.js.

9. Practical Project: Fetch API Data

Now we will retrieve user information from the JSONPlaceholder API and display it inside our React Native application.

Step 1: Import Required Components

Open App.js and add:

import React, { useEffect, useState } from "react";

import {
  View,
  Text,
  StyleSheet,
  FlatList,
  ActivityIndicator,
  Pressable,
} from "react-native";

Explanation:

  • useState stores API data and application states.

  • useEffect runs the API request when the screen loads.

  • FlatList displays a list of records.

  • ActivityIndicator displays a loading spinner.

  • Pressable creates a retry button.

Step 2: Create the Main Component

export default function App() {

  const [users, setUsers] = useState([]);

  const [loading, setLoading] = useState(true);

  const [error, setError] = useState("");

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>
        Student Data App
      </Text>
    </View>
  );
}

We have created three state variables:

  • users: Stores the API records.

  • loading: Indicates whether data is being loaded.

  • error: Stores an error message if the request fails.

Step 3: Create an API Function

Add this function inside the App component:

const fetchUsers = async (signal) => {

  try {

    setLoading(true);
    setError("");

    const response = await fetch(
      "https://jsonplaceholder.typicode.com/users",
      { signal }
    );

    if (!response.ok) {
      throw new Error("Unable to fetch user data.");
    }

    const data = await response.json();

    setUsers(data);

  } catch (error) {

    if (error.name !== "AbortError") {
      setError(error.message);
    }

  } finally {

    if (!signal?.aborted) {
      setLoading(false);
    }

  }
};

Explanation:

  1. async allows us to use asynchronous operations.

  2. await fetch() sends the API request.

  3. response.ok checks whether the HTTP response is successful.

  4. response.json() converts the response body into JavaScript data.

  5. setUsers(data) stores the retrieved records.

  6. catch handles request errors.

  7. finally handles the loading state after the request finishes.

Important: Fetch does not automatically throw an error for HTTP errors such as 404 or 500. Therefore, checking response.ok is important.

Step 4: Call the API Using useEffect

Add this code inside the App component:

useEffect(() => {

  const controller = new AbortController();

  fetchUsers(controller.signal);

  return () => {
    controller.abort();
  };

}, []);

Explanation:

  • useEffect() runs after the component mounts.

  • The empty dependency array means this effect runs when the component mounts.

  • AbortController allows us to cancel the request when the component unmounts.

  • The cleanup function prevents an outdated request from updating an unmounted screen.

Step 5: Display the Loading Indicator

Before displaying the main list, check whether data is loading:

if (loading) {

  return (
    <View style={styles.center}>
      <ActivityIndicator
        size="large"
        color="#2563EB"
      />

      <Text>Loading student data...</Text>
    </View>
  );

}

This provides feedback while the application waits for the server response.

Step 6: Display Error Messages

Add this condition after the loading condition:

if (error) {

  return (
    <View style={styles.center}>

      <Text style={styles.error}>
        {error}
      </Text>

      <Pressable
        style={styles.button}
        onPress={() => fetchUsers()}
      >
        <Text style={styles.buttonText}>
          Try Again
        </Text>
      </Pressable>

    </View>
  );

}

If the API request fails, the application displays an error message and a retry button.

Step 7: Display API Records Using FlatList

Replace the original return statement with:

return (
  <View style={styles.container}>

    <Text style={styles.heading}>
      Student Data App
    </Text>

    <FlatList
      data={users}
      keyExtractor={(item) => item.id.toString()}

      renderItem={({ item }) => (

        <View style={styles.card}>

          <Text style={styles.name}>
            {item.name}
          </Text>

          <Text>
            Username: {item.username}
          </Text>

          <Text>
            Email: {item.email}
          </Text>

          <Text>
            City: {item.address.city}
          </Text>

        </View>

      )}

    />

  </View>
);

Explanation:

  • data receives the array of API records.

  • keyExtractor generates a unique key for every item.

  • renderItem defines how each record appears.

  • item.name displays the user's name.

  • item.email displays the email address.

  • item.address.city accesses a nested JSON property.

10. Complete Fetch API Application Code

Replace your entire App.js file with this complete code:

import React, { useEffect, useState } from "react";

import {
  View,
  Text,
  StyleSheet,
  FlatList,
  ActivityIndicator,
  Pressable,
} from "react-native";

export default function App() {

  const [users, setUsers] = useState([]);

  const [loading, setLoading] = useState(true);

  const [error, setError] = useState("");

  const fetchUsers = async (signal) => {

    try {

      setLoading(true);
      setError("");

      const response = await fetch(
        "https://jsonplaceholder.typicode.com/users",
        { signal }
      );

      if (!response.ok) {
        throw new Error("Unable to fetch user data.");
      }

      const data = await response.json();

      setUsers(data);

    } catch (error) {

      if (error.name !== "AbortError") {
        setError(error.message);
      }

    } finally {

      if (!signal?.aborted) {
        setLoading(false);
      }

    }

  };

  useEffect(() => {

    const controller = new AbortController();

    fetchUsers(controller.signal);

    return () => {
      controller.abort();
    };

  }, []);

  if (loading) {

    return (
      <View style={styles.center}>

        <ActivityIndicator
          size="large"
          color="#2563EB"
        />

        <Text style={styles.loading}>
          Loading student data...
        </Text>

      </View>
    );

  }

  if (error) {

    return (
      <View style={styles.center}>

        <Text style={styles.error}>
          {error}
        </Text>

        <Pressable
          style={styles.button}
          onPress={() => fetchUsers()}
        >
          <Text style={styles.buttonText}>
            Try Again
          </Text>
        </Pressable>

      </View>
    );

  }

  return (

    <View style={styles.container}>

      <Text style={styles.heading}>
        Student Data App
      </Text>

      <Text style={styles.subtitle}>
        Students Retrieved From REST API
      </Text>

      <FlatList
        data={users}

        keyExtractor={(item) =>
          item.id.toString()
        }

        renderItem={({ item }) => (

          <View style={styles.card}>

            <Text style={styles.name}>
              {item.name}
            </Text>

            <Text style={styles.info}>
              Username: {item.username}
            </Text>

            <Text style={styles.info}>
              Email: {item.email}
            </Text>

            <Text style={styles.info}>
              City: {item.address.city}
            </Text>

          </View>

        )}

      />

    </View>

  );

}

const styles = StyleSheet.create({

  container: {
    flex: 1,
    backgroundColor: "#F1F5F9",
    padding: 20,
    paddingTop: 55,
  },

  center: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    padding: 20,
  },

  heading: {
    fontSize: 25,
    fontWeight: "bold",
    color: "#1E293B",
    marginBottom: 8,
  },

  subtitle: {
    fontSize: 14,
    color: "#64748B",
    marginBottom: 20,
  },

  loading: {
    marginTop: 12,
    color: "#334155",
  },

  card: {
    backgroundColor: "#FFFFFF",
    padding: 16,
    marginBottom: 14,
    borderRadius: 12,
    elevation: 3,
  },

  name: {
    fontSize: 18,
    fontWeight: "bold",
    color: "#2563EB",
    marginBottom: 8,
  },

  info: {
    fontSize: 14,
    color: "#475569",
    marginTop: 4,
  },

  error: {
    color: "#DC2626",
    fontSize: 16,
    marginBottom: 15,
    textAlign: "center",
  },

  button: {
    backgroundColor: "#2563EB",
    padding: 12,
    borderRadius: 8,
  },

  buttonText: {
    color: "#FFFFFF",
    fontWeight: "bold",
  },

});

11. Understand Axios in React Native

Now let's perform the same API operation using Axios.

Step 1: Install Axios

Open the terminal inside your project:

npm install axios

Step 2: Import Axios

Add this import to App.js:

import axios from "axios";

Step 3: Replace the Fetch Function

Replace the previous fetchUsers function with:

const fetchUsers = async (signal) => {

  try {

    setLoading(true);
    setError("");

    const response = await axios.get(
      "https://jsonplaceholder.typicode.com/users",
      {
        signal,
        timeout: 10000,
      }
    );

    setUsers(response.data);

  } catch (error) {

    if (error.code !== "ERR_CANCELED") {

      setError(
        error.response?.data?.message ||
        error.message ||
        "Something went wrong."
      );

    }

  } finally {

    if (!signal?.aborted) {
      setLoading(false);
    }

  }

};

The remaining application code, including useEffect, loading UI, error UI, FlatList and styles, can remain unchanged.

Step 4: Understand Axios Response

Axios provides several useful response properties:

  • response.data: Actual response body.

  • response.status: HTTP status code.

  • response.headers: Response headers.

  • response.config: Request configuration.

Example:

const response = await axios.get(
  "https://jsonplaceholder.typicode.com/users"
);

console.log(response.data);
console.log(response.status);

Axios automatically rejects unsuccessful HTTP status codes outside its accepted success range, unlike Fetch, which requires an explicit response.ok check.

12. Fetch API vs Axios

Feature Fetch Axios
Installation Built-in npm package
GET request Supported Supported
POST request Supported Supported
JSON handling response.json() response.data
HTTP error handling Manual status check Automatic rejection
Timeout Requires additional handling Built-in option
Interceptors Not built in Supported
Cancellation AbortController AbortController signal

Recommendation: Start with Fetch to understand the fundamentals of HTTP networking. Axios is useful when your application needs shared API configuration, interceptors, timeouts and more structured request handling.

13. Understanding POST API Requests

GET retrieves data. POST sends new information to the server.

Example using Fetch:

const createStudent = async () => {

  try {

    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts",
      {
        method: "POST",

        headers: {
          "Content-Type": "application/json",
        },

        body: JSON.stringify({
          title: "React Native Student",
          body: "Learning REST API",
          userId: 1,
        }),
      }
    );

    if (!response.ok) {
      throw new Error("Failed to create record.");
    }

    const result = await response.json();

    console.log(result);

  } catch (error) {

    console.log(error.message);

  }

};

The JSON.stringify() method converts a JavaScript object into a JSON string.

JSONPlaceholder is a testing service. Its simulated POST responses do not mean that permanent records are being saved.

14. Important API Development Concepts

A. Loading State

Always show a loading indicator while waiting for the server.

B. Error Handling

Handle:

  • Network connection failures.

  • Server errors.

  • Invalid responses.

  • Missing records.

  • Request timeouts.

C. API Base URL

For larger applications, keep the server URL in a central configuration file.

Example:

const BASE_URL =
  "https://jsonplaceholder.typicode.com";

D. API Authentication

Some APIs require:

  • API keys.

  • Access tokens.

  • Authorization headers.

  • Login sessions.

Never hardcode private production secrets into a mobile application.

E. Pagination

When an API returns thousands of records, avoid loading everything at once. Use pagination or infinite scrolling where the API supports it.

F. Secure Connections

Prefer HTTPS endpoints for production applications. Do not send sensitive credentials over unencrypted HTTP connections.

15. Common Errors and Solutions

Error 1: Network request failed

Possible reasons:

  • No internet connection.

  • Incorrect API URL.

  • Server unavailable.

  • HTTP networking restrictions.

Solution: Verify internet access and test the API URL independently.

Error 2: Cannot read property of undefined

Reason: The application is accessing a property that does not exist in the response.

Solution: Check the JSON structure and use safe property access where appropriate.

Error 3: Data is not displaying

Possible reasons:

  • API data is not stored in state.

  • Incorrect property names.

  • Incorrect FlatList configuration.

Solution: Log the response and inspect its structure.

Error 4: Loading indicator never disappears

Reason: Loading state is not updated in every request completion path.

Solution: Use finally to manage loading state.

Error 5: HTTP 404 or 500 is not caught by Fetch

Reason: Fetch does not automatically reject an HTTP error response.

Solution: Check response.ok and throw an error when it is false.

16. Practical Exercises

Complete these exercises to improve your understanding:

  1. Retrieve all users from the API.

  2. Display each user's name and email.

  3. Display the user's city.

  4. Retrieve a single user using /users/1.

  5. Display a loading spinner.

  6. Display an error message when the request fails.

  7. Add a retry button.

  8. Repeat the same application using Axios.

  9. Retrieve posts using /posts.

  10. Send a POST request with student information.

17. Conclusion

In this tutorial, we learned how React Native applications communicate with REST APIs.

We covered:

  • REST API fundamentals.

  • HTTP methods and JSON.

  • Fetch API.

  • Axios installation and usage.

  • Async/await.

  • useState and useEffect.

  • API loading and error states.

  • FlatList for displaying API records.

  • GET and POST requests.

  • API development best practices.

You have now built a React Native application that retrieves information from an external API and displays it on a mobile screen.

18. Frequently Asked Questions

Q1. What is a REST API in React Native?

A REST API allows a React Native application to communicate with a remote server through HTTP requests.

Q2. Is Fetch already available in React Native?

Yes. React Native provides Fetch for making network requests without installing an additional HTTP library.

Q3. Do we need to install Axios?

Yes. Axios is an external package and must be installed using npm or another supported package manager.

Q4. Which is better: Fetch or Axios?

Both are useful. Fetch is suitable for basic networking, while Axios offers additional conveniences such as interceptors and built-in timeout configuration.

Q5. What is async/await?

It is JavaScript syntax that makes asynchronous Promise-based operations easier to read and manage.

Q6. What is useEffect used for in API integration?

It is commonly used to trigger an API request when a component mounts or when specified dependencies change.

Q7. Why do we use FlatList?

FlatList efficiently renders lists of data and supports features such as scrolling and item virtualization.

Q8. Can React Native connect to a PHP and MySQL backend?

Yes. A PHP backend can expose REST API endpoints that retrieve or update information in a MySQL database. React Native can communicate with those endpoints using Fetch or Axios.

Q9. Does JSONPlaceholder permanently save new records?

No. It is a fake testing API designed for learning and prototyping.

Q10. Should API credentials be stored directly in React Native code?

Private production credentials should not be embedded in the mobile application. Use an appropriate backend and secure authentication strategy.

←
Post 21 of 39
→