Использование Axios с React Native
Это руководство по использованию Axios с React Native для управления запросами API. Чаще всего вам придется отправлять сетевые запросы к API при создании веб-приложения или мобильного приложения. Вы можете отправлять эти сетевые запросы для аутентификации пользователя, обновления ресурса или получения ресурса с вашего собственного сервера или сторонних API. Fetch API пригодится, если вы хотите отправлять запросы API в среде браузера.
React Native также имеет встроенный API-интерфейс Fetch, аналогичный браузерному, специально для взаимодействия с API вашего мобильного приложения. Однако существуют альтернативные библиотеки, такие как Axios, которые вы можете использовать вместо собственного Fetch API.
Кроме того, большинство разработчиков предпочитают Axios встроенному API выборки из-за его изоморфной природы и готового преобразования JSON. В этой статье вы узнаете, как управлять запросами API с помощью Axios в приложении React Native.
Введение в Axios
Axios — популярный изоморфный HTTP-клиент. Это означает, что он может работать в браузере и среде выполнения Node.js. В результате вы можете использовать одну и ту же кодовую базу для выполнения запросов API в Node.js, в браузере и в React Native.
Axios имеет несколько функций, таких как поддержка Promise API, автоматическое преобразование JSON и перехват сетевых запросов и ответов, среди прочего. Axios также является одним из самых простых в освоении и использовании HTTP-клиентов.
Сделать запрос API так же просто, как передать объект конфигурации в Axios или вызвать соответствующий метод с необходимыми аргументами. Для этого руководства мы будем использовать простое приложение React Native, настроенное с использованием управляемого рабочего процесса Expo.
Если у вас уже настроено приложение React Native, вы можете перейти к следующему разделу. В противном случае в документации React Native есть инструкции по настройке управляемого рабочего процесса Expo, которые помогут вам приступить к работе за считанные минуты.
Axios против Fetch API
Встроенные функции Axios делают его идеальным для крупных проектов с более сложными сетевыми требованиями. С другой стороны, Fetch API является встроенной функцией, устраняющей необходимость в обслуживании, обновлениях и проблемах с размером пакета, безопасностью и лицензированием, которые являются типичными факторами при использовании сторонних пакетов, таких как Axios.
Более того, большинство сред выполнения JavaScript также реализуют Fetch API. Таким образом, вы можете повторно использовать код, который вы пишете для React Native, с помощью Fetch API без изменений в браузере и других средах выполнения JavaScript, таких как Node и Deno.
Таким образом, встроенного API Fetch почти всегда будет достаточно для небольших проектов с базовыми требованиями к сети. Однако вам, возможно, придется выбрать Axios для крупных проектов со сложными сетевыми потребностями. Давайте еще раз посмотрим на различия между ними:
Установка Аксиоса
В зависимости от того, какой менеджер пакетов вы используете, введите одну из приведенных ниже команд в окне терминала и нажмите « Return» , чтобы установить Axios:
# axios npm install axios # yarn yarn add axios # pnpm pnpm add axios
Как делать запросы к API с помощью Axios
При вызове API с использованием Axios вы можете передать объект конфигурации в Axios или вызвать метод для соответствующей операции CRUD, которую вы хотите выполнить. Например, вы можете отправить запрос GET к конечной точке /api/users одним из следующих двух способов:
import axios from 'axios'; const baseUrl = 'https://reqres.in'; // Passing configuration object to axios axios({ method: 'get', url: `${baseUrl}/api/users/1`, }).then((response) => { console.log(response.data); }); // Invoking the get method to perform a GET request axios.get(`${baseUrl}/api/users/1`).then((response) => { console.log(response.data); });
Вы также можете использовать async/await
вместо использования цепочки обещаний, как в приведенном выше примере. Существует несколько других полей, таких как baseURL
, transformRequest
, transformResponse
, и headers
, среди прочих, которые вы можете включить в объект конфигурации, передаваемый Axios:
import axios from 'axios'; const baseUrl = 'https://reqres.in'; // Passing configuration object to axios const fetchUser = async () => { const configurationObject = { method: 'get', url: `${baseUrl}/api/users/1`, }; const response = await axios(configurationObject); console.log(response.data); }; // Invoking get method to perform a GET request const fetchUser = async () => { const url = `${baseUrl}/api/users/1`; const response = await axios.get(url); console.log(response.data); };
В отличие от встроенного Fetch API, Axios автоматически преобразует ответ в JSON.
Как сделать несколько одновременных запросов API с помощью Axios
Вы можете использовать Promise.all
или Promise.allSettled
установленный метод Promise API с Axios для выполнения нескольких одновременных запросов API из приложения React Native. Все запросы API будут успешными в приведенном ниже фрагменте кода; измените URI, переданный методу axios.get, на несуществующие, чтобы посмотреть, что произойдет, если некоторые запросы не будут успешными:
const concurrentRequests = [ axios.get(`${baseUrl}/api/users/1`), axios.get(`${baseUrl}/api/users/2`), axios.get(`${baseUrl}/api/users/3`), ]; // Using Promise.all Promise.all(concurrentRequests) .then((result) => { console.log(result); }) .catch((err) => { console.log(err); }); // Using Promise.allSettled Promise.allSettled(concurrentRequests) .then((result) => { console.log(result); }) .catch((err) => { console.log(err); });
Обратите внимание, что метод Promise.all
немедленно отклоняется, если отклоняется одно из Promises. Итак, используйте Promise.all
, если вы хотите, чтобы все запросы API были успешными или ни один из них не был выполнен. С другой стороны, Promise.allSettled
ожидает, что все входные обещания будут либо отклонены, либо выполнены. Затем вы можете проверить статус каждого объекта ответа fulfilled
или rejected
.
Как прервать сетевые запросы в Axios
Axios предоставляет функцию прерывания сетевых запросов. Типичным вариантом использования этой функции в React Native является отмена сетевых запросов в useEffect
хуке , когда компонент размонтирован, пока данные еще находятся в передаче. Вы можете прочитать фрагмент кода ниже, чтобы понять, как использовать эту функцию:
useEffect(() => { const abortController = new AbortController(); const url = `${baseUrl}/api/users/${userId}`; const fetchUsers = async () => { try { const response = await axios.get(url, { signal: abortController.signal }); console.log(response.data); } catch (error) { if(abortController.signal.aborted){ console.log('Data fetching cancelled'); }else{ // Handle error } } }; fetchUsers(); return () => abortController.abort("Data fetching cancelled"); }, [userId]);
Создание экземпляра Axios
Вы также можете создать экземпляр Axios с собственной конфигурацией. Затем используйте методы, предоставляемые экземпляром, для выполнения сетевых запросов. Axios объединит объект конфигурации, переданный при создании экземпляра, с конфигурацией, переданной в метод экземпляра:
const axiosInstance = axios.create({ baseURL: 'https://reqres.in/' }); axiosInstance.get('api/users/1').then((response) => { console.log(response.data); });
Использование Axios с React Native для управления запросами API
В этом разделе вы научитесь управлять запросами API с помощью Axios в приложении React Native. Вы будете использовать Axios для выполнения простой операции CRUD (создание, чтение, обновление и удаление).
Работа с ключами API в React Native
Для доступа к большинству сторонних API требуются секретные учетные данные. Хранить секретные ключи API в исходном коде на стороне клиента — не очень хорошая идея. Если вы это сделаете, любой, кто проверит код вашего прилагаемого приложения, получит доступ к вашему закрытому ключу. Один из рекомендуемых способов управления ключом API — создать уровень оркестрации между сторонним API и вашим приложением.
Например, бессерверная функция может безопасно получить доступ к вашему ключу API. Ваше приложение выполнит вызов конечной точки, предоставляемой бессерверной функцией.
Бессерверная функция обеспечит безопасный доступ к вашему ключу API, вызовет сторонний API, получит необходимый вам ресурс и передаст его в ваше мобильное приложение.
Управление состоянием приложения в цикле сетевой запрос-ответ
Когда вы инициируете сетевой запрос к API, запрос либо будет успешным, либо не удастся. Поэтому важно отслеживать различные состояния вашего приложения с момента запроса до получения ответа от сервера. Вы можете отображать индикатор загрузки, пока данные еще находятся в процессе передачи. Если операция CRUD прошла успешно, вы показываете пользователю сообщение об успехе. В случае неудачи вы отобразите соответствующее сообщение об ошибке.
Это важно, поскольку клиент, использующий ваше приложение, может иметь медленный доступ в Интернет или вообще не иметь его. Иногда сервер API может простаивать. Отслеживание состояния вашего приложения и отображение соответствующих сообщений обеспечат хороший UX.
В этой статье мы будем использовать reqres REST API. Это API-заполнитель, состоящий из фиктивных данных. Вы можете экспериментировать с конечными точками, используя инструменты тестирования API, такие как Postman или Insomnia.
Как отправлять запросы с помощью Axios в React Native
GET запрос
В этом разделе мы отправим запрос GET к конечной точке /api/users, чтобы получить пользователя. GET - это HTTP-метод, который вы используете, если хотите запросить ресурс с сервера. Мы сохраняем идентификатор пользователя в состоянии, как показано во фрагменте кода ниже. Вы можете изменить идентификатор пользователя внутри обработчика событий onPress, прикрепленного к кнопке "Создать нового пользователя". Изменение идентификатора пользователя вызовет запрос GET к API внутри useEffectHook.
После запуска сетевого запроса мы выводим на экран индикатор загрузки. Если мы успешно извлекаем данные, мы обновляем состояние и удаляем индикатор загрузки. Если по какой-либо причине нам не удается получить данные, мы останавливаем индикатор загрузки и выводим соответствующее сообщение об ошибке. Мы прерываем сетевой запрос в функции очистки, если пользователь решает закрыть приложение до получения ответа от сервера.
Проверьте возвращаемое значение функции effect в перехватчике useEffect. Вот как выглядит код для этого в App.js компонент:
import axios from "axios"; import React, { useState, useEffect } from "react"; import { StyleSheet, Text, ScrollView, View, Image, Platform, TouchableHighlight, } from "react-native"; import Constants from "expo-constants"; const baseUrl = "https://reqres.in"; function User({ userObject }) { return ( <View> <Image source={{ uri: userObject.avatar }} style={{ width: 200, height: 200, borderRadius: 100 }} /> <Text style={{ textAlign: "center", fontSize: 20 }}> {`${userObject.first_name} ${userObject.last_name}`} </Text> </View> ); } export default function App() { const [userId, setUserId] = useState(1); const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(false); const [hasError, setErrorFlag] = useState(false); const changeUserIdHandler = () => { setUserId((userId) => (userId === 3 ? 1 : userId + 1)); }; useEffect(() => { const abortController = new AbortController(); const url = `${baseUrl}/api/users/${userId}`; const fetchUsers = async () => { try { setIsLoading(true); const response = await axios.get(url, { signal: abortController.signal, }); if (response.status === 200) { setUser(response.data.data); setIsLoading(false); return; } else { throw new Error("Failed to fetch users"); } } catch (error) { if (abortController.signal.aborted) { console.log("Data fetching cancelled"); } else { setErrorFlag(true); setIsLoading(false); } } }; fetchUsers(); return () => abortController.abort("Data fetching cancelled"); }, [userId]); return ( <ScrollView contentContainerStyle={styles.container}> <View style={styles.wrapperStyle}> {!isLoading && !hasError && user && <User userObject={user} />} </View> <View style={styles.wrapperStyle}> {isLoading && <Text> Loading </Text>} {!isLoading && hasError && <Text> An error has occurred </Text>} </View> <View> <TouchableHighlight onPress={changeUserIdHandler} disabled={isLoading} style={styles.buttonStyles} > <Text style={styles.textStyles}>Get New User</Text> </TouchableHighlight> </View> </ScrollView> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "white", alignItems: "center", justifyContent: "center", marginTop: Platform.OS === "ios" ? 0 : Constants.statusBarHeight, }, wrapperStyle: { minHeight: 128, }, buttonStyles: { backgroundColor: "dodgerblue", }, textStyles: { fontSize: 20, color: "white", padding: 10, }, });
Приведенный выше код получит и отобразит имя и изображение пользователя на экране. На изображении ниже показано, как это выглядит в эмуляторе Android:
POST-запрос
В этом разделе вы узнаете, как сделать запрос на публикацию. POST - это HTTP-метод, который вы используете для отправки данных на сервер для обновления или создания ресурса. API-заполнитель, который мы используем, предоставляет конечную точку /api/users для создания ресурса. После успешного создания ресурса вы получите ответ с кодом состояния 201.
Выполнение запроса POST в Axios аналогично выполнению запроса GET. В большинстве случаев POST-запросы выполняются с использованием пользовательских данных, отправленных с помощью формы. Отправленные данные могут быть получены из форм входа, регистрации или форм обратной связи от ваших клиентов. Такие данные требуют проверки на стороне клиента перед отправкой.
Вы можете использовать один из пакетов форм для проверки данных при создании сложных приложений. Большинство пакетов хорошо спроектированы, оптимизированы и имеют большое сообщество. Однако прежде чем интегрировать библиотеку в ваше приложение, изучите возможные компромиссы. Особенно размер дополнительного пакета, который вы добавляете в свое приложение, и потенциальные уязвимости безопасности, которые он может создать.
Существует два основных пакета React для управления формами. Это пакеты Formik и React Hook Form . В приведенном ниже фрагменте кода у нас есть форма React Native для полного имени и адреса электронной почты пользователя.
Оба TextInput
компонента являются контролируемыми компонентами. В идеале, когда пользователь заполняет форму, вы выполняете проверку данных в режиме реального времени. Однако в данном случае это не тот случай, поскольку проверка данных формы выходит за рамки этой статьи.
После нажатия кнопки «Отправить»TextInput
поля и кнопка «Отправить» отключаются, прежде чем вы отобразите сообщение, показывающее, что вы создаете ресурс. Отключение кнопки отправки гарантирует, что пользователь не отправит несколько заявок. После успешной отправки запроса POST вы отображаете пользователю сообщение об успехе:
import axios from "axios"; import React, { useState } from "react"; import { StyleSheet, Text, ScrollView, View, Button, Platform, TextInput, } from "react-native"; import Constants from "expo-constants"; const baseUrl = "https://reqres.in"; export default function App() { const [fullName, setFullName] = useState(""); const [email, setEmail] = useState(""); const [isLoading, setIsLoading] = useState(false); const onChangeNameHandler = (fullName) => { setFullName(fullName); }; const onChangeEmailHandler = (email) => { setEmail(email); }; const onSubmitFormHandler = async (event) => { if (!fullName.trim() || !email.trim()) { alert("Name or Email is invalid"); return; } setIsLoading(true); try { const response = await axios.post(`${baseUrl}/api/users`, { fullName, email, }); if (response.status === 201) { alert(` You have created: ${JSON.stringify(response.data)}`); setIsLoading(false); setFullName(""); setEmail(""); } else { throw new Error("An error has occurred"); } } catch (error) { alert("An error has occurred"); setIsLoading(false); } }; return ( <ScrollView contentContainerStyle={styles.container}> <View> <View style={styles.wrapper}> {isLoading ? ( <Text style={styles.formHeading}> Creating resource </Text> ) : ( <Text style={styles.formHeading}>Create new user</Text> )} </View> <View style={styles.wrapper}> <TextInput placeholder="Full Name" placeholderTextColor="#ffffff" style={styles.input} value={fullName} editable={!isLoading} onChangeText={onChangeNameHandler} /> </View> <View style={styles.wrapper}> <TextInput placeholder="Your Email" placeholderTextColor="#ffffff" style={styles.input} value={email} editable={!isLoading} onChangeText={onChangeEmailHandler} /> </View> <View> <Button title="Submit" onPress={onSubmitFormHandler} disabled={isLoading} /> </View> </View> </ScrollView> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#252526", alignItems: "center", justifyContent: "center", marginTop: Platform.OS === "ios" ? 0 : Constants.statusBarHeight, }, formHeading: { color: "#ffffff", fontSize: 20, }, wrapper: { marginBottom: 10, }, input: { borderWidth: 2, borderColor: "grey", minWidth: 200, textAlignVertical: "center", paddingLeft: 10, borderRadius: 20, color: "#ffffff", }, });
Приведенный выше код отобразит форму с полями ввода имени и адреса электронной почты. Пользователь может заполнить форму и нажать кнопку отправки , чтобы сделать запрос POST. На изображении ниже показано, как это выглядит в эмуляторе Android:
На скриншоте выше заголовок формы - Создать нового пользователя. Однако после нажатия кнопки отправки заголовок меняется на Создание ресурса, а кнопка отправки отключена до завершения процесса:
PUT-запрос
Для обновления ресурса требуется метод PUT или PATCH, хотя я сосредоточусь на PUT. Если ресурс существует, использование метода PUT полностью перезаписывает его и создает новый ресурс, если его нет. С другой стороны, PATCH частично обновляет ресурс, если он существует, и ничего не делает, если его нет.
Выполнение запроса PUT к API аналогично выполнению запроса POST. Единственная разница заключается в объекте конфигурации, который вы передаете в Axios, или в методе HTTP, который вам нужно вызвать, чтобы отправить запрос PUT к API.
Вы можете заменить onSubmitFormHandler
запроса POST приведенным ниже кодом, чтобы сделать запрос PUT. Для полноты картины я использую цепочку обещаний, а не async/await
в обработчике событий ниже:
const onSubmitFormHandler = (event) => { if (!fullName.trim() || !email.trim()) { alert("Name or Email is invalid"); return; } setIsLoading(true); const configurationObject = { url: `${baseUrl}/api/users/2`, method: "PUT", data: { fullName, email }, }; axios(configurationObject) .then((response) => { if (response.status === 200) { alert(` You have updated: ${JSON.stringify(response.data)}`); setIsLoading(false); setFullName(""); setEmail(""); } else { throw new Error("An error has occurred"); } }) .catch((error) => { alert("An error has occurred"); setIsLoading(false); }); };
DELETE запрос
Вы можете отправлять запросы DELETE с помощью Axios так же, как вы делаете запросы POST и PUT. Как следует из названия, запрос DELETE удалит ресурс со стороны сервера. Вы можете заменить onSubmitFormHandler
код для выполнения запроса POST обработчиком событий ниже, чтобы выполнить запрос DELETE. Остальная часть кода остается прежней:
const onSubmitFormHandler = async (event) => { if (!fullName.trim() || !email.trim()) { alert("Name or Email is invalid"); return; } setIsLoading(true); try { const response = await axios.delete(`${baseUrl}/api/users/2`, { fullName, email, }); if (response.status === 204) { alert(` You have deleted: ${JSON.stringify(response.data)}`); setIsLoading(false); setFullName(''); setEmail(''); } else { throw new Error("Failed to delete resource"); } } catch (error) { alert("Failed to delete resource"); setIsLoading(false); } };
Как обрабатывать ошибки с помощью Axios
Как отмечалось выше, Axios основан на обещаниях. Когда обещание отклоняется, Axios вызывает обработчик отклонения и передает ему объект ошибки. Содержимое объекта ошибки зависит от ответа сервера. Если объект ошибки содержит это response
поле, ответ сервера имеет код состояния HTTP, выходящий за пределы успешного 2xx
диапазона. Таким образом, вы можете обновить пользовательский интерфейс, выдав соответствующее сообщение об ошибке.
Если объект ошибки содержит это request
поле, клиент сделал запрос, но не получил ответа от сервера. Однако если объект ошибки не имеет response
ни request
поля, это означает, что при настройке запроса произошла ошибка. Вы можете проверить наличие вышеуказанных условий в обработчике отклонения и предпринять соответствующие действия:
axios .get("https://reqres.in/api/users/1") .then((response) => { console.log(response.data); }) .catch((error) => { if (error.response) { // Update UI accordingly console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); } else if (error.request) { console.log(error.request); } else { console.log(`Error message: ${error.message}`); } });
Приведенный выше код использует цепочку обещаний. Вы можете переписать его, используя async/await
, следующим образом:
const fetchData = async (url) => { try { const response = await axios.get(url); console.log(response.data); } catch (error) { if (error.response) { // Update UI accordingly console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); } else if (error.request) { console.log(error.request); } else { console.log(`Error message: ${error.message}`); } } }; fetchData("https://reqres.in/api/users/1");
Заключение
Выполнение сетевых запросов к API неизбежно при создании мобильного приложения. Axios — один из самых популярных HTTP-клиентов, обладающий дополнительными функциями, максимально упрощающими работу в сети.