Типичные проблемы при работе с API в React Native
Что же, настало время обсудить типичные проблемы и ошибки, которые могут возникнуть при работе с API и AsyncStorage, а также пути их решения.
Ошибка №1: неверный обработчик ошибок
Нередко разработчики забывают обрабатывать ошибки при выполнении API-запросов. Например, если сервер отвечает кодом 404 или 500, приложение может просто "упасть". Представьте, вы нажали кнопку "Получить данные", а в ответ — просто белый экран. Это явно не то, чего хотелось бы пользователям.
Правильный подход заключается в проверке статуса ответа и обработке возможных ошибок:
const fetchData = async () => {
try {
const response = await fetch('https://example.com/api/data');
if (!response.ok) {
throw new Error(`Ошибка: ${response.status}`); // Проверка статуса
}
const data = await response.json();
console.log('Полученные данные:', data);
} catch (error) {
console.error('Ошибка при выполнении запроса:', error.message);
// Покажем пользователю понятное сообщение
Alert.alert('Ошибка', 'Не удалось загрузить данные. Попробуйте позже.');
}
};
Здесь мы проверяем response.ok и выбрасываем ошибку, если что-то пошло не так. Это позволяет унифицировать обработку ошибок.
Ошибка №2: асинхронный код "на свободе"
Когда вы используете async/await, важно помнить, что каждую асинхронную функцию нужно обернуть в try/catch. Если вы игнорируете это правило, то неперехваченные ошибки "пройдут мимо", и приложение может вести себя непредсказуемо.
Например, такой код:
const getData = async () => {
const response = await fetch('https://example.com/api/data');
const data = await response.json();
return data;
};
Если сервер недоступен, это приведет к ошибке, которая нигде не будет обработана. Всегда используйте try/catch или методы обработки ошибок, такие как .catch().
Ошибка №3: неразумный подход к повторным запросам
Если ваш API-запрос терпит неудачу, что вы делаете? Попробовать повторить его снова? Или паникуете? Здесь стоит внедрить стратегию повторных попыток:
const fetchDataWithRetries = async (url: string, retries: number = 3): Promise<any> => {
while (retries > 0) {
try {
const response = await fetch(url);
if (response.ok) return await response.json();
throw new Error(`Ошибка: ${response.status}`);
} catch (error) {
retries -= 1;
if (retries === 0) {
throw new Error('Превышено количество попыток');
}
console.log('Повтор запроса...');
}
}
};
Такой механизм полезен для временных сбоев, например, при плохом соединении.
Ошибка №4: забытая отмена запросов
При работе с fetch или Axios легко забыть, что запросы продолжают выполняться даже после того, как пользователь покинул экран. Это может привести к утечкам памяти или попыткам обновить состояние несуществующего компонента.
Для fetch решения нет, кроме реализации дополнительных механизмов, но с Axios становится проще:
import axios from 'axios';
const fetchData = async () => {
const source = axios.CancelToken.source();
try {
const response = await axios.get('https://example.com/api/data', {
cancelToken: source.token,
});
console.log(response.data);
} catch (error) {
if (axios.isCancel(error)) {
console.log('Запрос был отменён');
} else {
console.error(error);
}
}
return () => {
source.cancel('Операция отменена пользователем');
};
};
Ошибка №5: игнорирование CORS
Многие API требуют настроек CORS. Если вы видите ошибку "No Access-Control-Allow-Origin header", это связано с ограничениями браузера. Решение обычно кроется на стороне сервера. Но в случае мобильных приложений React Native это встречается реже, так как они не ограничиваются браузерными политикам.
Ошибки при использовании AsyncStorage
Ошибка №1: неправильная сериализация
AsyncStorage работает с данными в формате строки. Если вы пытаетесь сохранить объект без сериализации в JSON, это приведёт к ошибке или некорректным данным:
// Неправильно
await AsyncStorage.setItem('user', { name: 'John Doe' }); // Ошибка
// Правильно
await AsyncStorage.setItem('user', JSON.stringify({ name: 'John Doe' }));
И не забывайте "разбирать" данные обратно:
const user = await AsyncStorage.getItem('user');
const parsedUser = user ? JSON.parse(user) : null;
console.log(parsedUser.name);
Ошибка №2: отсутствие проверки данных
Часто данные из AsyncStorage считаются корректными по умолчанию, но это не всегда так:
const rawValue = await AsyncStorage.getItem('theme');
const theme = rawValue === 'dark' || rawValue === 'light' ? rawValue : 'light'; // Обрабатываем ошибку
Ошибка №3: Утечка памяти из-за выборки данных
AsyncStorage — асинхронная операция, и если её не завершить до размонтирования компонента, может возникнуть утечка памяти:
useEffect(() => {
let isMounted = true;
const loadData = async () => {
const data = await AsyncStorage.getItem('key');
if (isMounted) {
// Действие только если компонент ещё в DOM
setState(data);
}
};
loadData();
return () => { isMounted = false; }; // Флаг размонтирования
}, []);
Ошибка №4: проблемы с производительностью
Постоянное обращение к AsyncStorage внутри циклов или частая выборка данных может замедлить приложение. Старайтесь кэшировать данные в состоянии (useState или Redux):
useEffect(() => {
const fetchFromStorage = async () => {
const data = await AsyncStorage.getItem('key');
setData(data);
};
fetchFromStorage();
}, []);
// Используем `data` из состояния, а не извлекаем её снова при каждом рендере
Советы по оптимизации
1. Используйте библиотеки-обёртки
Для больших проектов есть смысл использовать библиотеки вроде react-query или redux-persist, которые автоматически кэшируют данные и упрощают работу с хранилищем.
2. Логируйте и анализируйте
Когда что-то идёт не так, полезно иметь хорошие логи. Например, добавьте сервисы Sentry или LogRocket для отслеживания ошибок в приложении.
3. Тестируйте асинхронность
Пользовательские тесты, эмуляция медленного соединения и даже инструменты вроде Postman помогут заранее выявить слабые места.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ