---
title: Redux и асинхронность
questionDates:
  q-transfer-0435: '2026-10-01'
  q-transfer-0456: '2026-10-01'
seo:
  description: >-
    Тема «Redux и асинхронность» для собеседования React Developer. Какие
    преимущества дает использование Redux для управления состоянием приложения?
    Что такое Redux Thunk?
  title: Redux и асинхронность — React Developer
---

[Все темы React Developer](/prep/react-developer)

## <strong>Какие преимущества дает использование</strong> <code>Redux</code> <strong>для управления состоянием приложения?</strong> [#q-14bee738d69b811aa2e1f7058a5fa6ea]

Преимущества использования <code>Redux</code> для управления состоянием приложения&#58;

{/* prettier-ignore */}
1. <strong>Предсказуемость состояния</strong>&#58;

    - Состояние приложения централизовано и управляется через чистые функции (редьюсеры), что делает поведение предсказуемым.

1. <strong>Отладка и инструменты</strong>&#58;

    - Redux DevTools предоставляет мощные инструменты для отладки и анализа изменений состояния.

1. <strong>Централизованное управление состоянием</strong>&#58;

    - В store хранится выбранное общее состояние. Локальное состояние интерфейса можно оставить в компонентах.

1. Чистые редьюсеры&#58;

    - Redux делает приложение более детерминированным, что упрощает тестирование и отладку.

1. <strong>Масштабируемость</strong>&#58;

    - Подходит для больших и сложных приложений благодаря четкой структуре и разделению логики.

1. <strong>Сообщество и экосистема</strong>&#58;

    - Большая поддержка со стороны сообщества и наличие множества middleware и инструментов.

:::note[Ссылки для изучения]

1. [Когда Redux полезен: предсказуемость состояния и компромиссы](https://reactdev.ru/libs/redux/faq/General/)
   :::

---

## <strong>Что такое</strong> <code>Redux Thunk</code><strong>?</strong> [#q-14bee738d69b81378f5ee83fd54b891c]

Redux Thunk позволяет передавать в dispatch функцию. Middleware вызывает её с dispatch и getState; внутри можно выполнять синхронную логику или асинхронную работу и отправлять обычные actions. Thunk action creator обычно возвращает такую функцию.

#### Основные функции&#58;

{/* prettier-ignore */}
1. <strong>Обработка асинхронных операций</strong>&#58;

    - Позволяет выполнять асинхронные запросы внутри действий.

    - Пример&#58;

        ```javascript
        const fetchData = () => {
          return async (dispatch) => {
            const response = await fetch('https://api.example.com/data');
            const data = await response.json();
            dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
          };
        };
        ```

1. <strong>Доступ к dispatch и getState</strong>&#58;

    - Позволяет внутри thunk-функции вызывать <code>dispatch</code> и <code>getState</code> для управления состоянием.

    - Пример&#58;

        ```javascript
        const fetchData = () => {
          return (dispatch, getState) => {
            const state = getState();
            // Логика на основе текущего состояния
          };
        };
        ```

Redux Thunk позволяет обрабатывать асинхронные действия и сложную логику внутри действий, расширяя возможности управления состоянием в Redux.

:::note[Ссылки для изучения]

1. [Redux Thunk: middleware для логики и побочных эффектов actions](https://reactdev.ru/libs/redux/faq/Actions/)
   :::

---

## <strong>Как работает</strong> <code>Redux Saga</code><strong>?</strong> [#q-14bee738d69b81b0882aee3a026a67a0]

<code>Redux Saga</code> — это middleware для управления побочными эффектами в
Redux с использованием генераторов ES6.

#### Основные функции&#58;

{/* prettier-ignore */}
1. <strong>Генераторы ES6</strong>&#58;

    - Использует функции-генераторы для управления асинхронным кодом.

    - Пример&#58;

        ```javascript
        import { call, put, takeEvery } from 'redux-saga/effects';

        function* fetchData() {
          try {
            const response = yield call(fetch, 'https://api.example.com/data');
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            const data = yield call([response, response.json]);
            yield put({ type: 'FETCH_DATA_SUCCESS', payload: data });
          } catch (error) {
            yield put({ type: 'FETCH_DATA_FAILURE', payload: error.message });
          }
        }

        function* watchFetchData() {
          yield takeEvery('FETCH_DATA_REQUEST', fetchData);
        }
        ```

1. <strong>Эффекты Saga</strong>&#58;

    - Операторы, такие как <code>call</code>, <code>put</code>, <code>takeEvery</code>, упрощают управление побочными эффектами.

    - Пример&#58;

        ```javascript
        function* fetchDataExample() {
          const response = yield call(fetch, 'https://api.example.com/data');
          if (!response.ok) throw new Error(`HTTP ${response.status}`);
          const data = yield call([response, response.json]);
          yield put({ type: 'FETCH_DATA_SUCCESS', payload: data });
        }
        ```

1. <strong>Создание Saga Middleware</strong>&#58;

    - Подключение saga middleware к Redux store.

    - Пример&#58;

        ```javascript
        import createSagaMiddleware from 'redux-saga';
        import { applyMiddleware, createStore } from 'redux';
        import rootSaga from './sagas';

        const sagaMiddleware = createSagaMiddleware();
        const store = createStore(reducer, applyMiddleware(sagaMiddleware));

        sagaMiddleware.run(rootSaga);
        ```

Redux Saga использует функции-генераторы для управления побочными эффектами в Redux, обеспечивая упрощенное и контролируемое выполнение асинхронных операций.

:::note[Ссылки для изучения]

1. [Декларативные эффекты Saga: call, put и тестирование генератора](https://ru.redux-saga.js.org/soderzhanie/introduction/beginnertutorial#delaem-nash-kod-testiruemym)
   :::

---

## <strong>Как реализовать ленивую загрузку</strong> <code>Redux</code><strong>-редьюсеров?</strong> [#q-14bee738d69b81aebad7ec5c975ca02e]

Для реализации ленивой загрузки <code>Redux</code>-редьюсеров используйте функцию <code>replaceReducer</code> и динамический импорт.

#### Шаги&#58;

{/* prettier-ignore */}
1. <strong>Создайте хранилище Redux с начальным редьюсером</strong>&#58;

    ```javascript
    import { createStore } from 'redux';
    const initialReducer = (state = {}, action) => state;
    const store = createStore(initialReducer);
    ```

1. <strong>Функция для добавления новых редьюсеров</strong>&#58;

    - Реализуйте функцию для динамического добавления редьюсеров.

    ```javascript
    const asyncReducers = {};

    const createRootReducer = (asyncReducers) => {
      return combineReducers({
        // добавьте синхронные редьюсеры здесь
        ...asyncReducers
      });
    };

    store.asyncReducers = asyncReducers;

    store.injectReducer = (key, asyncReducer) => {
      store.asyncReducers[key] = asyncReducer;
      store.replaceReducer(createRootReducer(store.asyncReducers));
    };
    ```

1. <strong>Динамический импорт редьюсера и его добавление</strong>&#58;

    ```javascript
    import { lazy } from 'react';

    const loadReducer = async (store) => {
      const { default: newReducer } = await import('./path/to/newReducer');
      store.injectReducer('newReducer', newReducer);
    };

    const MyComponent = lazy(() => import('./MyComponent'));
    ```

1. <strong>Использование в компоненте</strong>&#58;

    - Дождитесь loadReducer(store) до первого рендера компонента, читающего эту часть состояния. useEffect ниже запускается после первого commit и сам по себе этого не гарантирует.

    ```javascript
    useEffect(() => {
      loadReducer(store);
    }, []);
    ```

Для ленивой загрузки Redux-редьюсеров используйте <code>replaceReducer</code>, динамический импорт и функцию для добавления новых редьюсеров в хранилище.

:::note[Ссылки для изучения]

1. [replaceReducer: динамическая замена редьюсера store](https://reactdev.ru/libs/redux/api/Store/)
1. [Динамический import: получение экспорта редьюсера](https://learn.javascript.ru/modules-dynamic-imports)
   :::

---

## Как RTK Query управляет server state? [#q-transfer-0435]

RTK Query хранит server state по сериализованному ключу endpoint и аргументов. Одинаковые подписки используют одну cache entry, поэтому библиотека дедуплицирует активный запрос и раздаёт результат нескольким компонентам. Query предоставляет статусы загрузки, ошибки и данные, удерживает кеш пока есть подписчики и затем удаляет его по настройке. Mutation может инвалидировать теги, после чего связанные активные queries перезапрашиваются. Это не нормализованная бизнес-модель всего приложения и не вечный кеш. Правильность зависит от стабильных аргументов, схемы тегов и выбранной политики refetch.

:::note[Ссылки для изучения]

1. [RTK Query: API slice, кеш запросов и React-хуки](https://habr.com/ru/companies/domrf/articles/736336/)
   :::

---

## Чем RTK Query отличается от обычного Redux Toolkit? [#q-transfer-0456]

Redux Toolkit предоставляет primitives для обычного Redux state: `createSlice`, reducers, actions, middleware и store. RTK Query входит в Toolkit и решает lifecycle server state: выполняет запросы, хранит cache entries, дедуплицирует подписки, выдаёт статусы и инвалидирует данные тегами. Ручной slice нужен для клиентских бизнес-переходов, настроек UI или данных, которые не являются кешем сервера. Копировать query result в отдельный slice обычно создаёт два источника истины. При этом RTK Query не заменяет всю доменную модель: optimistic update и сложный workflow всё равно требуют явных решений.

:::note[Ссылки для изучения]

1. [RTK Query: API slice, кеш запросов и React-хуки](https://habr.com/ru/companies/domrf/articles/736336/)
   :::
