0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<h2>Проблематика работы с асинхронными запросами</h2>
1
<h2>Проблематика работы с асинхронными запросами</h2>
2
<p>Одна из самых сложных задач в построении фронтенд-приложений - работа с внешними запросами. Трудности приходят с двух сторон.</p>
2
<p>Одна из самых сложных задач в построении фронтенд-приложений - работа с внешними запросами. Трудности приходят с двух сторон.</p>
3
<p>С одной стороны, асинхронность сама по себе порождает неоднозначности, перестают работать стандартные механизмы. Redux не умеет работать в асинхронном режиме, поэтому вся обработка запросов происходит снаружи. В таком случае любая нетривиальная логика обработки асинхронных действий будет появляться внутри компонентов React:</p>
3
<p>С одной стороны, асинхронность сама по себе порождает неоднозначности, перестают работать стандартные механизмы. Redux не умеет работать в асинхронном режиме, поэтому вся обработка запросов происходит снаружи. В таком случае любая нетривиальная логика обработки асинхронных действий будет появляться внутри компонентов React:</p>
4
<p>С другой стороны, сеть - это вещь ненадежная. Запросы могут выполняться долго или не выполниться вообще, и все это нужно отслеживать для правильной реакции:</p>
4
<p>С другой стороны, сеть - это вещь ненадежная. Запросы могут выполняться долго или не выполниться вообще, и все это нужно отслеживать для правильной реакции:</p>
5
<ul><li>При долгих запросах - показывать спиннер</li>
5
<ul><li>При долгих запросах - показывать спиннер</li>
6
<li>При обрыве запроса - выводить соответствующее предупреждение</li>
6
<li>При обрыве запроса - выводить соответствующее предупреждение</li>
7
</ul><p>Добавим к примеру выше обработку ошибок и отслеживание статуса загрузки:</p>
7
</ul><p>Добавим к примеру выше обработку ошибок и отслеживание статуса загрузки:</p>
8
<p>Как мы видим, даже для небольшого числа вызовов придется написать очень много похожего кода. В реальных приложениях количество вызовов может измеряться многими десятками и даже сотнями. Поэтому без готового решения тут не обойтись. Для автоматизации HTTP-запросов к нам на помощь приходят два механизма:</p>
8
<p>Как мы видим, даже для небольшого числа вызовов придется написать очень много похожего кода. В реальных приложениях количество вызовов может измеряться многими десятками и даже сотнями. Поэтому без готового решения тут не обойтись. Для автоматизации HTTP-запросов к нам на помощь приходят два механизма:</p>
9
<ul><li>Мидлвара<em>redux-thunk</em>, которая уже включена в Redux Toolkit</li>
9
<ul><li>Мидлвара<em>redux-thunk</em>, которая уже включена в Redux Toolkit</li>
10
<li>Механизм createAsyncThunk()</li>
10
<li>Механизм createAsyncThunk()</li>
11
</ul><h2>Мидлвара redux-thunk</h2>
11
</ul><h2>Мидлвара redux-thunk</h2>
12
<p>Мидлвара - это код, который встраивается в обработку. Можно представить ее в виде цепочки функций, где каждая функция принимает данные из предыдущего обработчика и передает данные в следующую функцию. Каждая такая функция и будет мидлварой. Самый простой пример - это вывод логов. Такая функция будет выводить в лог данные и передавать дальше, никак их не меняя:</p>
12
<p>Мидлвара - это код, который встраивается в обработку. Можно представить ее в виде цепочки функций, где каждая функция принимает данные из предыдущего обработчика и передает данные в следующую функцию. Каждая такая функция и будет мидлварой. Самый простой пример - это вывод логов. Такая функция будет выводить в лог данные и передавать дальше, никак их не меняя:</p>
13
<p>Мидлвара<em>redux-thunk</em>добавляется в Redux и позволяет использовать асинхронный код внутри dispatch(). С ее помощью выносят логику выполнения запросов и обновления хранилища в отдельные функции (<em>thunks</em>). Вот пример такой функции:</p>
13
<p>Мидлвара<em>redux-thunk</em>добавляется в Redux и позволяет использовать асинхронный код внутри dispatch(). С ее помощью выносят логику выполнения запросов и обновления хранилища в отдельные функции (<em>thunks</em>). Вот пример такой функции:</p>
14
<p>Вообще thunk необязательно должен быть асинхронным. Thunk - это всего лишь функция, которая возвращает другую функцию и принимает dispatch и getState (при необходимости) в качестве параметров. Thunk может выполнять синхронные действия или комбинации синхронных и асинхронных операций, но в этом уроке нам это не так важно.</p>
14
<p>Вообще thunk необязательно должен быть асинхронным. Thunk - это всего лишь функция, которая возвращает другую функцию и принимает dispatch и getState (при необходимости) в качестве параметров. Thunk может выполнять синхронные действия или комбинации синхронных и асинхронных операций, но в этом уроке нам это не так важно.</p>
15
<p>Код из примера выше можно реализовать и без<em>redux-thunk</em>, просто написав асинхронную функцию. Ей на вход мы передадим dispatch:</p>
15
<p>Код из примера выше можно реализовать и без<em>redux-thunk</em>, просто написав асинхронную функцию. Ей на вход мы передадим dispatch:</p>
16
<p>Разница проявляется в более продвинутых вариантах использования - например, когда мы работаем с состоянием или глобальными объектами. В этом случае не обойтись без<em>redux-thunk</em>:</p>
16
<p>Разница проявляется в более продвинутых вариантах использования - например, когда мы работаем с состоянием или глобальными объектами. В этом случае не обойтись без<em>redux-thunk</em>:</p>
17
<p>Основное отличие здесь - это возможность передачи дополнительных параметров в thunk-функцию через extraArgument, а также быстро получить текущее состояние хранилища с помощью функции getState.</p>
17
<p>Основное отличие здесь - это возможность передачи дополнительных параметров в thunk-функцию через extraArgument, а также быстро получить текущее состояние хранилища с помощью функции getState.</p>
18
<h2>Механизм createAsyncThunk()</h2>
18
<h2>Механизм createAsyncThunk()</h2>
19
<p>Несмотря на удобства<em>redux-thunk</em>, сами по себе thunks не уменьшают количество кода. Та же обработка ошибок всё еще составляет большую его часть. Здесь на помощь приходит инструмент createAsyncThunk(), появившийся вместе с redux-toolkit:</p>
19
<p>Несмотря на удобства<em>redux-thunk</em>, сами по себе thunks не уменьшают количество кода. Та же обработка ошибок всё еще составляет большую его часть. Здесь на помощь приходит инструмент createAsyncThunk(), появившийся вместе с redux-toolkit:</p>
20
<p>Каждый thunk, созданный через createAsyncThunk(), содержит внутри себя три события:</p>
20
<p>Каждый thunk, созданный через createAsyncThunk(), содержит внутри себя три события:</p>
21
<ul><li><em>pending</em></li>
21
<ul><li><em>pending</em></li>
22
<li><em>fulfilled</em></li>
22
<li><em>fulfilled</em></li>
23
<li><em>rejected</em></li>
23
<li><em>rejected</em></li>
24
</ul><p>Они соответствуют состояниям промиса и вызываются в Redux Toolkit в тот момент, когда промис переходит в одно из этих состояний. Нам не обязательно реагировать на все. Мы сами выбираем, что нам важно в приложении.</p>
24
</ul><p>Они соответствуют состояниям промиса и вызываются в Redux Toolkit в тот момент, когда промис переходит в одно из этих состояний. Нам не обязательно реагировать на все. Мы сами выбираем, что нам важно в приложении.</p>
25
<h2>Применение thunk</h2>
25
<h2>Применение thunk</h2>
26
<p>Thunk выходит за рамки обработки асинхронных запросов. Этот механизм можно использовать в различных сценариях, где требуется вынос сложной логики или побочных эффектов из компонентов. Thunk также оказывается полезным для написания логики, зависящей от состояния в Redux. Ещё одним важным аспектом использования Thunk является возможность отправки нескольких действий в определенный момент или в течение заданного времени.</p>
26
<p>Thunk выходит за рамки обработки асинхронных запросов. Этот механизм можно использовать в различных сценариях, где требуется вынос сложной логики или побочных эффектов из компонентов. Thunk также оказывается полезным для написания логики, зависящей от состояния в Redux. Ещё одним важным аспектом использования Thunk является возможность отправки нескольких действий в определенный момент или в течение заданного времени.</p>
27
<p>При этом Thunk дополняет, а не заменяет useEffect, который по-прежнему может использоваться для работы с побочными эффектами в компонентах. Если необходимо выделить какую-то логику из компонента, чтобы сделать его более универсальным для повторного использования, эту логику можно перенести в Thunk вместо использования useEffect.</p>
27
<p>При этом Thunk дополняет, а не заменяет useEffect, который по-прежнему может использоваться для работы с побочными эффектами в компонентах. Если необходимо выделить какую-то логику из компонента, чтобы сделать его более универсальным для повторного использования, эту логику можно перенести в Thunk вместо использования useEffect.</p>
28
<p>На практике useEffect и createAsyncThunk часто используются вместе. Например, вызов dispatch(fetchData()) внутри useEffect с пустым массивом зависимостей позволяет подгрузить данные при инициализации компонента, обеспечивая эффективное взаимодействие между асинхронными операциями и жизненным циклом компонента.</p>
28
<p>На практике useEffect и createAsyncThunk часто используются вместе. Например, вызов dispatch(fetchData()) внутри useEffect с пустым массивом зависимостей позволяет подгрузить данные при инициализации компонента, обеспечивая эффективное взаимодействие между асинхронными операциями и жизненным циклом компонента.</p>
29
<h2>Что дальше</h2>
29
<h2>Что дальше</h2>
30
<p>В современной разработке вместе с React часто используется TypeScript. Вы можете познакомиться с ним в курсе<a>Основы Typescript</a>.</p>
30
<p>В современной разработке вместе с React часто используется TypeScript. Вы можете познакомиться с ним в курсе<a>Основы Typescript</a>.</p>