Что такое Redux и как он работает в React?

MiddleReact · Frontend·Обновлено 19 июля 2026
Коротко
Redux — это предсказуемый контейнер состояния для JavaScript-приложений, основанный на трёх принципах: единое хранилище, состояние только для чтения и изменения через чистые функции. В React он подключается через библиотеку react-redux, предоставляющую компоненты Provider и хуки useSelector/useDispatch.

Что такое Redux

Redux — библиотека для управления глобальным состоянием приложения. Она не привязана к React, но чаще всего используется именно с ним через пакет react-redux.

Redux строится на трёх фундаментальных принципах:

  • Единственный источник истины — всё состояние приложения хранится в одном объекте (store).
  • Состояние только для чтения — изменить состояние можно только через отправку (dispatch) действия (action).
  • Изменения через чистые функции — редьюсеры (reducer) описывают, как действие изменяет состояние, и не имеют побочных эффектов.

Ключевые понятия

Store

Центральное хранилище всего состояния. Создаётся один раз через configureStore (Redux Toolkit) или createStore.

Action

Простой объект с обязательным полем type, описывающий намерение изменить состояние.

Reducer

Чистая функция (state, action) => newState. Получает текущее состояние и действие, возвращает новое состояние. Никогда не мутирует исходный объект.

Dispatch

Метод store для отправки действий. После вызова dispatch(action) Redux передаёт действие в редьюсер и обновляет состояние.

Selector

Функция для извлечения нужного куска состояния из store. Хук useSelector подписывает компонент на изменения.

Поток данных

UI → dispatch(action) → reducer(state, action) → новый state → UI

Поток строго однонаправленный: это делает поведение приложения предсказуемым и легко отлаживаемым.

Пример с Redux Toolkit

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

// Описываем срез состояния
const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    // Внутри RTK можно «мутировать» — Immer делает это безопасно
    increment(state) {
      state.value += 1
    },
    addByAmount(state, action: PayloadAction<number>) {
      state.value += action.payload
    },
  },
})

export const { increment, addByAmount } = counterSlice.actions

export const store = configureStore({
  reducer: { counter: counterSlice.reducer },
})

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

Подключение к React

import { Provider } from 'react-redux'
import { store } from './store'

// Оборачиваем приложение в Provider
function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  )
}
import { useSelector, useDispatch } from 'react-redux'
import { increment, addByAmount } from './counterSlice'
import type { RootState, AppDispatch } from './store'

function Counter() {
  // Читаем состояние — компонент перерендерится при его изменении
  const count = useSelector((state: RootState) => state.counter.value)
  const dispatch = useDispatch<AppDispatch>()

  return (
    <div>
      <span>{count}</span>
      <button onClick={() => dispatch(increment())}>+1</button>
      <button onClick={() => dispatch(addByAmount(5))}>+5</button>
    </div>
  )
}

Когда использовать Redux

Redux оправдан, когда состояние действительно глобальное (авторизация, корзина, фильтры), когда несколько несвязанных компонентов должны реагировать на одни данные, или когда важна воспроизводимость и возможность time-travel дебаггинга через Redux DevTools.

Что хочет услышать интервьюер

Понимание трёх принципов Redux: единый store, иммутабельность, чистые редьюсеры

Знание однонаправленного потока данных: action → reducer → store → UI

Умение объяснить роли каждой сущности (store, action, reducer, dispatch, selector)

Знакомство с Redux Toolkit как современным стандартом — configureStore, createSlice

Понимание, когда Redux нужен, а когда достаточно Context или useState

Пример: Слайс и store (Redux Toolkit)

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

interface CounterState {
  value: number
}

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 } as CounterState,
  reducers: {
    increment(state) {
      state.value += 1 // Immer разрешает «мутацию» внутри createSlice
    },
    addByAmount(state, action: PayloadAction<number>) {
      state.value += action.payload
    },
    reset(state) {
      state.value = 0
    },
  },
})

export const { increment, addByAmount, reset } = counterSlice.actions

export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  },
})

// Типы для использования в хуках
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

Пример: Подключение и использование в компонентах

import React from 'react'
import { Provider, useSelector, useDispatch } from 'react-redux'
import { store, increment, addByAmount, reset } from './store'
import type { RootState, AppDispatch } from './store'

// Типизированные хуки — лучше вынести в отдельный файл hooks.ts
const useAppSelector = useSelector.withTypes<RootState>()
const useAppDispatch = useDispatch.withTypes<AppDispatch>()

function Counter() {
  const count = useAppSelector((state) => state.counter.value)
  const dispatch = useAppDispatch()

  return (
    <div>
      <p>Счётчик: {count}</p>
      <button onClick={() => dispatch(increment())}>+1</button>
      <button onClick={() => dispatch(addByAmount(10))}>+10</button>
      <button onClick={() => dispatch(reset())}>Сбросить</button>
    </div>
  )
}

export function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  )
}

Типичные ошибки

Мутация состояния напрямую в редьюсере вместо возврата нового объекта

Использование Redux для локального состояния форм или UI-флагов, где достаточно useState

Незнание Redux Toolkit — кандидат описывает только устаревший шаблон с `createStore` и `combineReducers`

Путаница между action creator и action — кандидат не разграничивает функцию и объект

Отсутствие типизации store и useSelector в TypeScript-проекте

Лучшие курсы по теме

изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Feature-Sliced Design

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.5
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее