Обработка асинхронного состояния

В мобильных приложениях часто требуется загружать данные из сети: список пользователей, постов, товаров и т.п. Такие операции асинхронны, и состояние компонента должно отражать разные этапы этого процесса: ожидание, успех или ошибку.

Типичная структура состояния

Для корректной обработки асинхронных операций рекомендуется использовать три переменные состояния:

  • loading — флаг загрузки,
  • data — полученные данные,
  • error — информация об ошибке (если произошла).

Пример инициализации:

const [loading, setLoading] = useState(true);
const [data, setData] = useState<User[] | null>(null);
const [error, setError] = useState<string | null>(null);

Пример загрузки данных

Загрузка обычно выполняется внутри эффекта (useEffect) при монтировании компонента:

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

type User = {
  id: number;
  name: string;
};

export default function UsersScreen() {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState<User[] | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users');
        if (!response.ok) throw new Error('Ошибка сети');
        const users: User[] = await response.json();
        setData(users);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Неизвестная ошибка');
      } finally {
        setLoading(false);
      }
    };

    fetchUsers();
  }, []);

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

  if (error) {
    return <Text>Ошибка: {error}</Text>;
  }

  return (
    <View>
      {data?.map(user => (
        <Text key={user.id}>{user.name}</Text>
      ))}
    </View>
  );
}

Отображение состояний в интерфейсе

  • Во время загрузки показывается индикатор (ActivityIndicator).
  • При ошибке — сообщение об ошибке.
  • При успехе — отображаются данные.

Такой подход обеспечивает предсказуемое поведение интерфейса и улучшает пользовательский опыт.

Важные замечания

  • Не забывайте вызывать setLoading(false) в блоке finally, чтобы скрыть индикатор даже при ошибке.
  • Избегайте хранения только одного состояния (например, status: 'idle' | 'loading' | 'success' | 'error') без дополнительных данных — это усложняет рендеринг.
  • Для повторной загрузки (например, по кнопке «Повторить») вынесите логику в отдельную функцию и вызывайте её при необходимости.