JavaRush /Курсы /Модуль 3: React /Создание действий (actions) и редьюсеров для изменения со...

Создание действий (actions) и редьюсеров для изменения состояния

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

Что такое действия (actions)?

Action — это "вещь", которая говорит Redux, что именно вы хотите изменить в состоянии. Action — обычный объект, содержащий два обязательных поля:

  1. type — строка, уникально описывающая действие.
  2. payload (опционально) — данные, передаваемые вместе с действием.

Пример типичного Action:

{
  type: 'todos/addTodo',
  payload: {
    id: 1,
    title: 'Изучить Redux',
    completed: false
  }
}

Можно представить это как "приказ" для Redux: "Эй, добавь новую задачу в список!"

Что такое редьюсеры (reducers)?

Reducer — это чистая функция, которая отвечает за обновление состояния, основываясь на переданном действии. Представьте, что это маленькая фабрика обновлений: она берет текущее состояние и действие, а затем возвращает новое состояние.

Вот пример простого редьюсера:

const initialState = { count: 0 };

const counterReducer = (state = initialState, action: { type: string }) => {
  switch (action.type) {
    case 'counter/increment':
      return { ...state, count: state.count + 1 };
    case 'counter/decrement':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

Создание действий и редьюсеров с помощью Redux Toolkit

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

Давайте создадим пример функциональности для списка задач.

1. Настройка Slice

Создадим Slice для управления задачами. Начнем с определения начального состояния:

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

interface TodoState {
  todos: Todo[];
}

const initialState: TodoState = {
  todos: []
};

Теперь создаем Slice:

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

const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    addTodo: (state, action: PayloadAction<Todo>) => {
      state.todos.push(action.payload);
    },
    toggleTodo: (state, action: PayloadAction<number>) => {
      const todo = state.todos.find((todo) => todo.id === action.payload);
      if (todo) {
        todo.completed = !todo.completed;
      }
    },
    removeTodo: (state, action: PayloadAction<number>) => {
      state.todos = state.todos.filter((todo) => todo.id !== action.payload);
    }
  }
});

Что здесь происходит?

  • name: уникальное имя Slice.
  • initialState: начальное состояние.
  • reducers: набор функций, которые обновляют состояние. Каждая функция автоматически создает соответствующее действие.

2. Генерация действий

С помощью createSlice действия создаются автоматически. Вы можете получить их через поле actions:

export const { addTodo, toggleTodo, removeTodo } = todosSlice.actions;

Теперь вы можете отправлять эти действия из компонентов:

dispatch(addTodo({
  id: 1,
  title: 'Изучить Redux Toolkit',
  completed: false
}));

dispatch(toggleTodo(1)); // Переключить состояние задачи с id = 1

dispatch(removeTodo(1)); // Удалить задачу с id = 1

3. Подключение редьюсера к Store

Не забудьте добавить редьюсер вашего Slice в Store:

import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './todosSlice';

const store = configureStore({
  reducer: {
    todos: todosReducer
  }
});

Особенности и типизация

Благодаря TypeScript и функциям Redux Toolkit, типизация действий становится почти "бесплатной". Все действия, созданные с помощью createSlice, автоматически имеют строгую типизацию.

Например, addTodo имеет следующий тип:

(type: 'todos/addTodo', payload: Todo)

Так же работает для других действий.

Практическое задание: расширяем функциональность

Попробуйте самостоятельно добавить возможность редактирования задачи. Вот подсказка:

  1. Создайте новый редьюсер editTodo, который будет принимать id задачи и новый title как payload.
  2. Реализуйте логику редактирования задачи в массиве todos.

Код для подсказки:

editTodo: (state, action: PayloadAction<{ id: number; title: string }>) => {
  const todo = state.todos.find((todo) => todo.id === action.payload.id);
  if (todo) {
    todo.title = action.payload.title;
  }
}

Типичные ошибки (и как их избегать)

  1. Изменение состояния напрямую: Redux требует, чтобы состояние было неизменяемым. Но функции в createSlice используют Immer под капотом, который позволяет изменять состояния так, будто они изменяемые. Если вы не используете Redux Toolkit — не забудьте о Object.assign или операторах развертки ....

  2. Поломка типов: следите за строгой типизацией PayloadAction. Не оставляйте payload без типа, иначе TypeScript может сильно расстроиться.

  3. Дублирование логики: действия и редьюсеры должны быть короткими и независимыми. Не пытайтесь затолкать весь бизнес-слой в редьюсер!

Реальное применение

Итак, зачем все это нужно? Разработка на Redux Toolkit полезна в реальных проектах, особенно когда вы имеете дело со сложным состоянием, например:

  • Взаимодействие с API для загрузки данных.
  • Управление формами с несколькими уровнями валидации.
  • Построение масштабируемых приложений с несколькими независимыми подмодулями.

Теперь, после освоения этой темы, вы можете смело использовать Redux Toolkit для любых сложных задач управления состоянием.

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