← Назад к вопросам

Что такое редьюсер?

2.0 Middle🔥 121 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Редьюсер — это ключевая концепция в функциональном программировании и современных JavaScript-библиотеках управления состоянием, прежде всего в Redux и встроенном хуке React useReducer. В самом общем смысле редьюсер — это чистая функция, которая принимает текущее состояние (state) и действие (action), а возвращает новое состояние. Название происходит от метода массива Array.prototype.reduce(), который выполняет схожую операцию: "сворачивает" (to reduce) коллекцию значений в одно итоговое значение.

Основные принципы работы

Функция-редьюсер обязана следовать строгим правилам:

  1. Чистота (Purity): Функция не должна иметь побочных эффектов (сайд-эффектов). Она не может:
    *   Изменять свои аргументы (state или action).
    *   Выполнять асинхронные операции (API-запросы, таймауты).
    *   Генерировать случайные значения (например, `Math.random()`).
    *   Обращаться к глобальным переменным или внешним состояниям.

  1. Детерминированность: При одинаковых аргументах (state и action) функция ВСЕГДА возвращает один и тот же результат.

  2. Структура сигнатуры: Редьюсер всегда имеет одну и ту же сигнатуру:

    function reducer(state, action) {
      // Логика обновления состояния на основе action
      return newState;
    }
    

Типичная реализация в Redux/useReducer

Редьюсер анализирует тип переданного действия (action.type) и возвращает обновленную копию состояния. Обработка неизвестных действий должна возвращать неизмененное состояние.

// Пример редьюсера для управления состоянием списка задач (todos)
const initialState = {
  todos: [],
  filter: 'all'
};

function todoReducer(state = initialState, action) {
  switch (action.type) {
    case 'ADD_TODO':
      // Важно: НЕ мутируем state, а возвращаем новый объект!
      return {
        ...state, // Копируем все поля текущего состояния
        todos: [
          ...state.todos, // Копируем старый массив задач
          { id: Date.now(), text: action.payload, completed: false } // Добавляем новую
        ]
      };

    case 'TOGGLE_TODO':
      return {
        ...state,
        // Проходим по массиву и обновляем только нужный элемент
        todos: state.todos.map(todo =>
          todo.id === action.payload
            ? { ...todo, completed: !todo.completed } // Создаем новый объект задачи
            : todo
        )
      };

    case 'SET_FILTER':
      return {
        ...state,
        filter: action.payload // Обновляем поле filter
      };

    // На случай неизвестного action — возвращаем state без изменений
    default:
      return state;
  }
}

// Использование с useReducer в React
import { useReducer } from 'react';

function TodoApp() {
  const [state, dispatch] = useReducer(todoReducer, initialState);

  const handleAdd = (text) => {
    dispatch({ type: 'ADD_TODO', payload: text });
  };
  // ... остальной компонент
}

Связь с методом Array.reduce()

Чтобы понять происхождение термина, рассмотрим аналогию:

// Array.reduce: сворачиваем массив в одно число (сумму)
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((accumulator, currentValue) => {
  return accumulator + currentValue; // Функция-редьюсер для чисел
}, 0); // Начальное значение accumulator = 0
// Результат: 10

// Redux-подобный редьюсер: сворачиваем поток действий (actions) в одно состояние (state)
const actions = [
  { type: 'ADD', value: 1 },
  { type: 'SUBTRACT', value: 2 },
  { type: 'ADD', value: 3 }
];

const initialState = 0;

const finalState = actions.reduce((currentState, action) => {
  if (action.type === 'ADD') return currentState + action.value;
  if (action.type === 'SUBTRACT') return currentState - action.value;
  return currentState;
}, initialState);
// Результат: 2 (0 + 1 - 2 + 3)

Здесь функция, передаваемая в reduce, — это и есть редьюсер. Она принимает текущий аккумулятор (состояние) и текущий элемент (действие), возвращая новое значение аккумулятора.

Почему редьюсеры так важны?

  • Предсказуемость: Поскольку они чистые, поведение системы полностью детерминировано. Легко понять, как состояние изменилось в ответ на действие.
  • Тестируемость: Редьюсеры невероятно просто тестировать. Нужно лишь передать state и action и проверить возвращаемое значение.
  • Девидуализация логики: Вся бизнес-логика обновления состояния сосредоточена в одном месте, а не размазана по компонентам.
  • Отладка (Time Travel): Такие инструменты, как Redux DevTools, полагаются на предсказуемость редьюсеров, чтобы позволить "перематывать" и "воспроизводить" действия для отладки.
  • Структурирование сложных состояний: Для больших приложений редьюсеры можно комбинировать (combine reducers), разделяя ответственность за разные части состояния.

Комбинирование редьюсеров

В больших приложениях принято создавать несколько специализированных редьюсеров для разных доменов состояния, а затем объединять их с помощью утилиты combineReducers (в Redux) или вручную.

// Редьюсер для задач
function todosReducer(state = [], action) { /* ... */ }

// Редьюсер для фильтра видимости
function visibilityFilterReducer(state = 'all', action) { /* ... */ }

// Корневой редьюсер, комбинирующий их (аналог combineReducers)
function rootReducer(state = {}, action) {
  return {
    todos: todosReducer(state.todos, action),
    visibilityFilter: visibilityFilterReducer(state.visibilityFilter, action)
  };
}

Итог: Редьюсер — это фундаментальный строительный блок паттерна Flux/Redux и концепции управления состоянием через один источник истины (single source of truth). Он инкапсулирует логику трансформации состояния, делая её предсказуемой, тестируемой и независимой от UI-слоя, что критически важно для поддержки и масштабирования сложных frontend-приложений.

Что такое редьюсер? | PrepBro