JavaRush /Курсы /Модуль 3: React /Введение в Redux Thunk — работа с асинхронными запросами

Введение в Redux Thunk — работа с асинхронными запросами

Модуль 3: React
7 уровень , 1 лекция
Открыта

Что такое Redux Thunk?

Redux Thunk — это библиотека, которая позволяет нам выполнять асинхронные действия внутри Redux. Давайте упростим: в обычной ситуации Redux работает только с синхронными действиями. То есть, вы отправляете dispatch действие — и оно сразу попадает в редьюсер. Однако, если вам нужно подождать, например, ответа от сервера, Redux сам по себе не сможет это сделать.

Вот тут на сцену выходит Thunk! Он предоставляет возможность отправлять функции вместо объектов-действий. Эти функции, в свою очередь, могут выполнять асинхронные операции и отправлять другие действия в Redux.

Представьте, что Redux — это ресторан. Официант (Redux) берёт ваш заказ (действие) и передаёт его на кухню (редьюсер). Но если ваше блюдо ещё не готово (асинхронные запросы), официант теряется. Redux Thunk — это шеф-повар, который может дождаться готовности блюда (завершения запроса) и только потом передать его на кухню.

Установка Redux Thunk

Первый шаг — добавить Thunk в наш проект. Для этого просто установите библиотеку:

npm install redux-thunk

Теперь подключим его к нашему Store. Откроем файл с настройкой Redux Store (например, store.ts):

import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';

const store = configureStore({
  reducer: {
    // ваши редьюсеры
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(thunk),
});

export default store;

Вот и всё, Thunk подключён! Лёгкая победа.

Как работает Thunk?

Redux Thunk позволяет вам отправлять в dispatch не только действия, но и функции. Эти функции принимают два аргумента:

  • dispatch — чтобы отправлять действия.
  • getState — чтобы получить текущее состояние.

Пример простой Thunk-функции:

const fetchData = () => {
  return async (dispatch, getState) => {
    dispatch({ type: 'FETCH_DATA_START' }); // Начать загрузку данных
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const data = await response.json();
      dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data }); // Успешная загрузка
    } catch (error) {
      dispatch({ type: 'FETCH_DATA_FAILURE', error }); // Ошибка загрузки
    }
  };
};

Эта функция:

  1. Стартует загрузку данных.
  2. Выполняет асинхронный запрос с помощью fetch.
  3. По завершении отправляет в Redux новое действие с результатом FETCH_DATA_SUCCESS или FETCH_DATA_FAILURE.

Теперь внедрим это в наше приложение. Допустим, мы разрабатываем простое приложение, отображающее список статей.

1. Создадим редьюсер

Файл: features/posts/postsSlice.ts

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface Post {
  id: number;
  title: string;
  body: string;
}

interface PostsState {
  loading: boolean;
  posts: Post[];
  error: string | null;
}

const initialState: PostsState = {
  loading: false,
  posts: [],
  error: null,
};

const postsSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {
    fetchPostsStart(state) {
      state.loading = true;
      state.error = null;
    },
    fetchPostsSuccess(state, action: PayloadAction<Post[]>) {
      state.loading = false;
      state.posts = action.payload;
    },
    fetchPostsFailure(state, action: PayloadAction<string>) {
      state.loading = false;
      state.error = action.payload;
    },
  },
});

export const { fetchPostsStart, fetchPostsSuccess, fetchPostsFailure } =
  postsSlice.actions;

export default postsSlice.reducer;

2. Создадим Thunk

Файл: features/posts/postsThunks.ts

import { fetchPostsStart, fetchPostsSuccess, fetchPostsFailure } from './postsSlice';
import { AppDispatch } from '../../store';

export const fetchPosts = () => {
  return async (dispatch: AppDispatch) => {
    dispatch(fetchPostsStart()); // Начало загрузки
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const data = await response.json();
      dispatch(fetchPostsSuccess(data)); // Успех
    } catch (error: any) {
      dispatch(fetchPostsFailure(error.message)); // Ошибка
    }
  };
};

3. Интеграция с компонентом

Теперь используем созданный Thunk в компоненте React.

Файл: components/PostsList.tsx

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchPosts } from '../features/posts/postsThunks';
import { RootState } from '../store';

const PostsList: React.FC = () => {
  const dispatch = useDispatch();
  const { posts, loading, error } = useSelector((state: RootState) => state.posts);

  useEffect(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error: {error}</p>;
  }

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
};

export default PostsList;

Что мы получили?

Теперь наше приложение:

  1. Отправляет асинхронный запрос.
  2. Использует Thunk для управления состоянием загрузки и ошибок.
  3. Динамически обновляет интерфейс на основе ответа от API.

Какие типичные ошибки бывают?

Итак, Redux Thunk — это мощный инструмент, но есть несколько подводных камней. Во-первых, не забывайте ловить ошибки при запросах. Если пропустить блок catch, ваше приложение может упасть из-за необработанного исключения.

Во-вторых, следите за тем, чтобы не допустить гонки состояний. Например, если пользователь отправляет несколько запросов подряд, старые данные могут перезаписать новые. Для таких случаев лучше хранить ID активного запроса и игнорировать результаты старых.

Зачем это нужно на практике?

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

  • Подгрузка данных с сервера при загрузке страницы.
  • Отправка форм на сервер и обработка ошибок.
  • Управление пользователем: вход/выход, проверка токенов.

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

1
Задача
Модуль 3: React, 7 уровень, 1 лекция
Недоступна
Создание Thunk для асинхронного запроса
Создание Thunk для асинхронного запроса
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ