Урок 10

Алерты и обратная связь

Как сообщать пользователю о событиях: алерты, toast, модалки, индикаторы загрузки.

Alert

Встроенный модуль. Работает на iOS и Android.

import { Alert } from 'react-native';

Alert.alert('Заголовок', 'Сообщение');

Alert.alert(
    'Удалить?',
    'Это действие нельзя отменить',
    [
        { text: 'Отмена', style: 'cancel' },
        { text: 'Удалить', style: 'destructive', onPress: () => deleteItem() },
    ]
);

Стили кнопок: default, cancel, destructive.

ActivityIndicator

Спиннер загрузки:

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

<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
    <ActivityIndicator size="large" color="#c1442e" />
</View>

size: 'small' или 'large'.

Toast на Android

import { ToastAndroid, Platform } from 'react-native';

if (Platform.OS === 'android') {
    ToastAndroid.show('Сохранено', ToastAndroid.SHORT);
}

На iOS нет — используй алерты или сторонние библиотеки.

Сторонние библиотеки

react-native-toast-message — универсальный toast:

npm install react-native-toast-message
import Toast from 'react-native-toast-message';

// в корне приложения
<Toast />

// вызов
Toast.show({
    type: 'success',
    text1: 'Сохранено',
    text2: 'Пост опубликован',
});

react-native-flash-message — альтернатива с большими возможностями.

Модальные окна

import { Modal, View, Text, Pressable } from 'react-native';

<Modal
    visible={isOpen}
    animationType="slide"  // 'slide', 'fade', 'none'
    transparent
    onRequestClose={() => setOpen(false)}
>
    <View style={styles.overlay}>
        <View style={styles.content}>
            <Text>Модальное окно</Text>
            <Pressable onPress={() => setOpen(false)}>
                <Text>Закрыть</Text>
            </Pressable>
        </View>
    </View>
</Modal>

Skeleton

Заглушки пока грузятся данные. Библиотеки: react-native-skeleton-placeholder, moti/skeleton.

import { Skeleton } from 'moti/skeleton';

<Skeleton colorMode="light" width={200} height={20} />

Empty state

Пустой список:

<FlatList
    data={items}
    ListEmptyComponent={
        <View style={styles.empty}>
            <Text style={styles.emptyTitle}>Пока пусто</Text>
            <Text style={styles.emptyText}>Начните добавлять записи</Text>
        </View>
    }
    renderItem={...}
/>

Error state

function ErrorState({ error, onRetry }: { error: Error; onRetry: () => void }) {
    return (
        <View style={styles.error}>
            <Text style={styles.errorTitle}>Ошибка</Text>
            <Text style={styles.errorText}>{error.message}</Text>
            <Pressable onPress={onRetry}>
                <Text>Повторить</Text>
            </Pressable>
        </View>
    );
}

Уведомления об успехе

async function save() {
    try {
        await api.create(data);
        Toast.show({ type: 'success', text1: 'Сохранено' });
    } catch (e) {
        Toast.show({ type: 'error', text1: 'Ошибка', text2: (e as Error).message });
    }
}

Если ты уже знаешь React

В вебе — alert(), window.confirm(), кастомные компоненты. В React Native — Alert.alert, Modal, Toast. Логика похожа, API другой.

Итоги

  • Alert.alert для диалогов
  • ActivityIndicator для загрузки
  • ToastAndroid на Android
  • react-native-toast-message универсально
  • Modal для кастомных окон
  • Skeleton для лучшего UX