Работа с сетью: загрузка данных через fetch

Подключаем приложение к интернету: загружаем данные с сервера и грамотно показываем загрузку и ошибки.

fetch — встроенная функция для сетевых запросов; в React Native она работает так же, как в браузере, и обычно вызывается из useEffect.

fetch встроен

Хорошая новость: fetch в React Native доступен «из коробки», как в браузере. Никаких библиотек для базовых запросов не нужно. Он возвращает Promise, поэтому используем async/await.

async function loadUsers() {
  const response = await fetch("https://api.example.com/users");
  const data = await response.json();
  return data;
}

Загрузка в useEffect

Данные обычно грузят при появлении экрана — то есть в useEffect с пустым массивом зависимостей. Результат кладут в состояние.

import { useState, useEffect } from "react";
import { FlatList, Text } from "react-native";

function Users() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch("https://api.example.com/users")
      .then((res) => res.json())
      .then((data) => setUsers(data));
  }, []);

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

Три состояния экрана с данными

Любая загрузка проходит через три состояния, и каждое нужно показать пользователю:

СостояниеЧто показать
загрузкаиндикатор (спиннер)
успехданные
ошибкасообщение и кнопку «повторить»

Индикатор загрузки

ActivityIndicator — встроенный крутящийся спиннер. Его показывают, пока идёт запрос.

import { ActivityIndicator } from "react-native";

function Loading() {
  return <ActivityIndicator size="large" color="tomato" />;
}

Полный пример с тремя состояниями

import { useState, useEffect } from "react";
import { View, Text, ActivityIndicator } from "react-native";

function Screen() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch("https://api.example.com/data")
      .then((res) => {
        if (!res.ok) throw new Error("Ошибка сервера");
        return res.json();
      })
      .then((json) => setData(json))
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <ActivityIndicator size="large" />;
  if (error) return <Text>Ошибка: {error}</Text>;
  return <Text>Данные загружены</Text>;
}

Обратите внимание на проверку res.ok: fetch не считает ошибкой ответ 404 или 500, поэтому статус проверяют вручную и при беде бросают исключение, которое поймает catch.

Обработка ответа — обычный JS

Логику разбора ответа можно отработать на чистом JS (запускаемый пример):

function handleResponse(status, body) {
  if (status === 200) return "Данные: " + body;
  if (status === 404) return "Не найдено";
  return "Ошибка сервера";
}

console.log(handleResponse(200, "[users]"));
console.log(handleResponse(404, ""));
console.log(handleResponse(500, ""));

Вывод:

Данные: [users]
Не найдено
Ошибка сервера

Итог

  • fetch встроен в RN; данные грузят в useEffect и кладут в состояние.
  • Показывайте все три состояния: загрузка (ActivityIndicator), успех, ошибка.
  • fetch не бросает ошибку на 404/500 — проверяйте res.ok вручную.
Проверьте себя
1. Нужна ли отдельная библиотека для базовых сетевых запросов в RN?
AДа, обязательно axios
BНет, fetch встроен и работает как в браузере
CДа, только expo-network
DНет, но запросы делать нельзя
2. Где обычно запускают загрузку данных при появлении экрана?
AВ renderItem
BВ useEffect с пустым массивом зависимостей
CВ StyleSheet.create
DВ keyExtractor
3. Почему важно проверять res.ok при работе с fetch?
Afetch всегда падает с ошибкой
Bfetch не считает ошибкой статусы 404 и 500, поэтому их проверяют вручную
Cres.ok ускоряет запрос
DБез этого данные не загрузятся вообще
Поддержать проект