Navigation & DataCore· 40 min read

Loading Data from an API

Use fetch inside useEffect to load data when a screen opens, then show it in a list.

What you will learn

  • Fetch data with fetch and async/await
  • Run it once on load with useEffect
  • Show a loading state, then the data

Same fetch, same useEffect

Most apps show data that lives on a server somewhere — a list of users, products or posts. To get it, your app talks to an API (Application Programming Interface — a way for one program to ask another program for data over the internet). The reply usually comes back as JSON (JavaScript Object Notation — a simple text format for objects and lists that looks just like JavaScript).

Loading data works just like web React: call fetch (the built-in function that sends a request to a URL) to get that JSON, and run it inside useEffect so it happens once when the screen opens. You keep the result and a loading flag in state.

Think of it as a three-step relay: ask the server (fetch), wait for the reply, then show what came back. While you wait you display a spinner so the screen never looks frozen or blank.

What the data looks like

Before the code, it helps to know the shape of what the server sends back. The free test API jsonplaceholder.typicode.com/users returns an array of user objects like this:

A peek at the JSON the API returns — an array of objects
[
  { "id": 1, "name": "Leanne Graham", "email": "leanne@april.biz" },
  { "id": 2, "name": "Ervin Howell",  "email": "ervin@melissa.tv" }
]

Note: Output: (This is sample data, not program output.) Each object has an id, a name and an email. That is why, in the next code, item.name shows the person’s name — it reads the name field from one of these objects.

Load and show users

Here we fetch those users, show a spinner while waiting, then list the names:

fetch in useEffect, with a loading spinner then a list
import { useState, useEffect } from 'react';
import { FlatList, Text, ActivityIndicator, View } from 'react-native';

export default function App() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((res) => res.json())
      .then((data) => {
        setUsers(data);
        setLoading(false);
      });
  }, []);   // [] = run once when the screen opens

  if (loading) return <ActivityIndicator size="large" />;

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

Note: Output: A spinner appears for a moment, then a scrollable list of names like: Leanne Graham Ervin Howell Clementine Bauch ... The empty array [] at the end of useEffect means "run once". Without it, the fetch could loop forever.

The whole request–response flow, step by step

A request is your app asking the server for data; the response is what the server sends back. (HTTP — HyperText Transfer Protocol — is just the agreed language phones and servers use to make that request and reply.) Here is the full trip our code takes, in order:

  1. The screen first draws with users empty and loading set to true, so the if (loading) line shows the spinner (ActivityIndicator).
  2. When the screen opens, useEffect runs once (because of the []) and calls fetch('https://jsonplaceholder.typicode.com/users') — the request goes out over the internet.
  3. Your app waits. The spinner keeps spinning so the screen never looks frozen.
  4. The server replies with the text of the JSON list. .then((res) => res.json()) turns that raw text into a real JavaScript array of objects.
  5. The next .then((data) => ...) receives that array. setUsers(data) stores the users in state and setLoading(false) turns the spinner off.
  6. Those two state changes re-render the component. Now loading is false, so the if is skipped and the FlatList runs instead.
  7. The FlatList draws one Text per user, showing item.name — the names you see on screen.

Watch out: Never forget the dependency array. useEffect(fn) with no array runs after every render, so a fetch that sets state would trigger another render and fetch again — an endless loop. Use useEffect(fn, []) to run once.

Tip: Real networks fail sometimes. Wrap the fetch in try/catch (or add a .catch) and keep an error state so you can show a friendly "Could not load" message instead of a blank screen.

Q. What does the empty array [] at the end of useEffect do?

Answer: An empty dependency array tells the effect to run a single time when the component first appears — perfect for loading data once.

✍️ Practice

  1. Change the URL to /posts and show each post’s title.
  2. Add a .catch that logs an error and an error state with a fallback message.

🏠 Homework

  1. Fetch a list from any free public API and display three fields from each item in a FlatList.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →