# Axios и Redux-Thunk, асинхронные запросы к бэкенду ## fetch Привычный способ обращения к серверу - функция fetch: ```js const response = await fetch(url, options); const json = await response.json(); ``` ## Axios возвращает Promise Как и fetch, axios возвращает Promise. Синтаксис немного отличается: ```js const response = await fetch(url, options); const json = await response.json(); ``` ## В чём разница? - корректная поддержка cookie-заголовков - более гибкие настройки - более выразительный интерфейс ## Установка npm: ```sh npm install axios ``` yarn: ```sh yarn add axios ``` ## Общие запросы ```js // Send a POST request axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } }); // Send a GET request (default method) axios('/user/12345'); ``` ## Запросы по методам - axios.request(config) - axios.get(url[, config]) - axios.delete(url[, config]) - axios.head(url[, config]) - axios.options(url[, config]) - axios.post(url[, data[, config]]) - axios.put(url[, data[, config]]) - axios.patch(url[, data[, config]]) ## Настройки ```js { url: '/user', method: 'get', // default // базовый адрес, к нему добавляется свойство url для формирования полного адреса baseURL: 'https://some-domain.com/api/', // преобразование всех запросов перед отправкой transformRequest: [function (data, headers) { return data; }], // преобразование ответа transformResponse: [function (data) { // Do whatever you want to transform the data return data; }], // дополнительные заголовки headers: {'X-Requested-With': 'XMLHttpRequest'}, // параметры в адресной строке, GET-параметры params: { ID: 12345 }, // данные для не GET-запросов (POST, PUT и тд), сюда передаётся тело запроса data: { firstName: 'Fred' }, // передача данных в виде строки data: 'Country=Brasil&City=Belo Horizonte', // таймаут соединения timeout: 1000, // default is `0` (no timeout) // передача cookie-файлов withCredentials: false, // default // 401-авторизация auth: { username: 'janedoe', password: 's00pers3cret' }, // обработка полученных данных перед отдачей результата // options are: 'arraybuffer', 'document', 'json', 'text', 'stream', 'blob' responseType: 'json', // default // ограничение размера передаваемого содержимого maxContentLength: 2000, maxBodyLength: 2000, // максимальное число переходов по переадресациям от сервера maxRedirects: 21, // default // инструменты для отмены запроса // an alternative way to cancel Axios requests using AbortController signal: new AbortController().signal, } ``` ## Ответ axios возвращает ответ в виде объекта со следующими свойствами ```js axios.get('/user/12345') .then(function (response) { console.log(response.data); console.log(response.status); console.log(response.statusText); console.log(response.headers); console.log(response.config); }); ``` ## Отмена запроса ```js const controller = new AbortController(); axios.get('/foo/bar', { signal: controller.signal }).then(function(response) { //... }); // cancel the request controller.abort() ``` ## Настройки в рамках клиента Для разделения настроек при работе с несколькими API, можно создать свой экземпляр axios через axios.create ```js const instance = axios.create(); instance.defaults.timeout = 2500; instance.get('/longRequest', { timeout: 5000 }); ``` ## Шаблон Посредник Представляет цепочку функций: - каждая обрабатывает свою часть запроса - если в процессе проверки возникают ошибки, следующие в цепочке функции не запустятся ```js const user = { name: 'Oleg', age: 18, active: true }; const checkAge = (data, next) => { if (data.age >= 18) { return next(); } console.log('Вы слишком молоды!'); } const checkLastName = (data, next) => { if (data.lastName) { return next(); } console.log('У вас нет фамилии!'); } const checkActive = (data, next) => { if (data.active) { return next(); } console.log('Будьте активнее!'); }; const action = (data) => { console.log('вы справились!'); } const middlewares = [checkAge, checkLastName, checkActive, action]; const run = (payload, chain) => { const done = () => true; for (const fn of chain) { if (fn(payload, done) !== true) { return; } } } run(user, middlewares); ``` ## Redux Thunk По факту входит в состав redux toolkit и позволяет запускать дочерние и отложенные действия ```js export const incrementIfOdd = (amount) => (dispatch, getState) => { const currentValue = selectCount(getState()); if (currentValue % 2 === 1) { dispatch(incrementByAmount(amount)); } }; ``` ## Преимущества - Запуск действий из действий (цепочка действий) - Даёт доступ к dispatch - Поддержка Promise в действиях