17. Сеть и API запросы
React Native поддерживает стандартный fetch API. Используй Axios для удобства и React Query для кеширования.
fetch — базовый запрос
Заголовок раздела «fetch — базовый запрос»const fetchUser = async (id: number) => { try { const response = await fetch(`https://api.example.com/users/${id}`); if (!response.ok) throw new Error(`HTTP ${response.status}`); return await response.json(); } catch (error) { console.error('Ошибка:', error); throw error; }};npx expo install axiosimport axios from 'axios';
const api = axios.create({ baseURL: 'https://api.example.com', timeout: 10000, headers: { 'Content-Type': 'application/json' },});
// Интерсептор для токенаapi.interceptors.request.use(async (config) => { const token = await SecureStore.getItemAsync('token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config;});
// Запросыconst users = await api.get('/users');await api.post('/users', { name: 'Яша' });await api.put(`/users/${id}`, { name: 'Yasha' });await api.delete(`/users/${id}`);React Query (TanStack Query)
Заголовок раздела «React Query (TanStack Query)»npx expo install @tanstack/react-queryimport { QueryClient, QueryClientProvider, useQuery, useMutation } from '@tanstack/react-query';
const queryClient = new QueryClient();
// Провайдер в App<QueryClientProvider client={queryClient}> <Navigation /></QueryClientProvider>
// Запросfunction UserProfile({ userId }) { const { data, isLoading, error, refetch } = useQuery({ queryKey: ['user', userId], queryFn: () => api.get(`/users/${userId}`), staleTime: 5 * 60 * 1000, });
if (isLoading) return <ActivityIndicator />; if (error) return <Text>Ошибка: {error.message}</Text>; return <Text>{data.name}</Text>;}
// Мутацияconst { mutate, isPending } = useMutation({ mutationFn: (data) => api.post('/posts', data), onSuccess: () => queryClient.invalidateQueries({ queryKey: ['posts'] }),});NetInfo — состояние сети
Заголовок раздела «NetInfo — состояние сети»npx expo install @react-native-community/netinfoimport NetInfo from '@react-native-community/netinfo';
// Текущее состояниеconst state = await NetInfo.fetch();console.log(state.isConnected); // true/falseconsole.log(state.type); // 'wifi' | 'cellular' | 'none'
// Слушать измененияconst unsubscribe = NetInfo.addEventListener(state => { if (!state.isConnected) Alert.alert('Нет интернета');});Offline banner
Заголовок раздела «Offline banner»function useOnlineStatus() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { const unsub = NetInfo.addEventListener(s => setIsOnline(s.isConnected ?? true)); return unsub; }, []); return isOnline;}
function OfflineBanner() { const isOnline = useOnlineStatus(); if (isOnline) return null; return ( <View style={styles.banner}> <Text>📡 Нет интернета</Text> </View> );}// React Web-эквивалент React Native кода// fetch() с loading, error и даннымиimport { useState } from 'react';
export default function App() { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null);
const fetchUser = async () => { setLoading(true); setError(null); try { const res = await fetch('https://jsonplaceholder.typicode.com/users/1'); if (!res.ok) throw new Error('HTTP ' + res.status); setData(await res.json()); } catch (e) { setError(e.message); } finally { setLoading(false); } };
return ( <div style={{ padding: 24, fontFamily: 'system-ui' }}> <h3>Networking: fetch()</h3> <button onClick={fetchUser} disabled={loading} style={{ padding: '10px 20px', fontSize: 16, cursor: 'pointer' }}> {loading ? 'Загрузка...' : 'Загрузить пользователя'} </button> {error && <p style={{ color: 'red' }}>Ошибка: {error}</p>} {data && ( <div style={{ marginTop: 12, background: '#f0f0f0', padding: 12, borderRadius: 8 }}> <p><b>{data.name}</b></p> <p>{data.email}</p> <p>{data.phone}</p> </div> )} </div> );}