PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Карьерные пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Zustand vs Redux Toolkit: что выбрать в 2024 году

    Zustand vs Redux Toolkit: что выбрать в 2024 году

    Аватар автора Zustand vs Redux Toolkit: что выбрать в 2024 году

    Антон Ларичев

    Иконка календаря26 апреля 2026
    ReactState ManagementZustandRedux ToolkitJavaScriptmiddleИконка уровня middle
    Картинка поста Zustand vs Redux Toolkit: что выбрать в 2024 году

    Введение

    Управление состоянием — одна из ключевых задач в любом React-приложении. Долгое время Redux был стандартом де-факто, но сегодня у него появился серьёзный конкурент — Zustand. Оба инструмента решают одну задачу, но делают это принципиально по-разному.

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

    Архитектура и философия

    Redux Toolkit

    Redux Toolkit (RTK) — это официальный набор инструментов для работы с Redux. Он построен на принципах Flux-архитектуры: единственный глобальный store, иммутабельные обновления через reducers и строгий однонаправленный поток данных.

    RTK значительно упрощает работу с Redux: убирает шаблонный код, встраивает Immer для мутабельных обновлений и предоставляет RTK Query для работы с API.

    Zustand

    Zustand — минималистичная библиотека на основе хуков. Она не навязывает строгую архитектуру: вы создаёте store как обычный JavaScript-объект с состоянием и действиями. Под капотом используется паттерн наблюдателя и контекст React не нужен вовсе.

    Сравнение на практике

    Установка и начало работы

    # Redux Toolkit
    npm install @reduxjs/toolkit react-redux
    
    # Zustand
    npm install zustand
    

    Создание хранилища: Redux Toolkit

    import { createSlice, configureStore, PayloadAction } from '@reduxjs/toolkit';
    
    // Определяем тип состояния
    interface CounterState {
      value: number;
    }
    
    const initialState: CounterState = { value: 0 };
    
    // Создаём slice с редьюсерами и экшенами
    const counterSlice = createSlice({
      name: 'counter',
      initialState,
      reducers: {
        increment: (state) => {
          state.value += 1; // Immer позволяет писать мутации
        },
        decrement: (state) => {
          state.value -= 1;
        },
        setValue: (state, action: PayloadAction<number>) => {
          state.value = action.payload;
        },
      },
    });
    
    export const { increment, decrement, setValue } = counterSlice.actions;
    
    // Настраиваем глобальный store
    export const store = configureStore({
      reducer: {
        counter: counterSlice.reducer,
      },
    });
    
    export type RootState = ReturnType<typeof store.getState>;
    export type AppDispatch = typeof store.dispatch;
    
    // Провайдер оборачивает всё приложение
    import { Provider } from 'react-redux';
    import { store } from './store';
    
    function App() {
      return (
        <Provider store={store}>
          <Counter />
        </Provider>
      );
    }
    
    import { useDispatch, useSelector } from 'react-redux';
    import { increment, decrement } from './counterSlice';
    import { RootState } from './store';
    
    function Counter() {
      const value = useSelector((state: RootState) => state.counter.value);
      const dispatch = useDispatch();
    
      return (
        <div>
          <span>{value}</span>
          <button onClick={() => dispatch(increment())}>+</button>
          <button onClick={() => dispatch(decrement())}>-</button>
        </div>
      );
    }
    

    Создание хранилища: Zustand

    import { create } from 'zustand';
    
    // Типизируем store
    interface CounterStore {
      value: number;
      increment: () => void;
      decrement: () => void;
      setValue: (val: number) => void;
    }
    
    // Создаём store — всё в одном месте
    const useCounterStore = create<CounterStore>((set) => ({
      value: 0,
      increment: () => set((state) => ({ value: state.value + 1 })),
      decrement: () => set((state) => ({ value: state.value - 1 })),
      setValue: (val) => set({ value: val }),
    }));
    
    // Никаких провайдеров не нужно — используем хук напрямую
    function Counter() {
      const { value, increment, decrement } = useCounterStore();
    
      return (
        <div>
          <span>{value}</span>
          <button onClick={increment}>+</button>
          <button onClick={decrement}>-</button>
        </div>
      );
    }
    

    Асинхронные операции

    RTK предоставляет createAsyncThunk для работы с API:

    import { createAsyncThunk } from '@reduxjs/toolkit';
    
    // Асинхронный thunk для загрузки данных пользователя
    export const fetchUser = createAsyncThunk(
      'user/fetchById',
      async (userId: string) => {
        const response = await fetch(`/api/users/${userId}`);
        return response.json();
      }
    );
    

    В Zustand асинхронные действия — просто async-функции:

    interface UserStore {
      user: User | null;
      loading: boolean;
      fetchUser: (id: string) => Promise<void>;
    }
    
    const useUserStore = create<UserStore>((set) => ({
      user: null,
      loading: false,
      // Асинхронное действие — обычная async-функция
      fetchUser: async (id) => {
        set({ loading: true });
        const response = await fetch(`/api/users/${id}`);
        const user = await response.json();
        set({ user, loading: false });
      },
    }));
    

    Производительность и селекторы

    RTK использует reselect для мемоизированных селекторов:

    import { createSelector } from '@reduxjs/toolkit';
    
    // Мемоизированный селектор — пересчитывается только при изменении зависимостей
    const selectFilteredItems = createSelector(
      (state: RootState) => state.items.list,
      (state: RootState) => state.items.filter,
      (list, filter) => list.filter(item => item.category === filter)
    );
    

    Zustand решает проблему лишних перерендеров через подписку на конкретные части состояния:

    // Компонент перерендерится только при изменении поля value
    const value = useCounterStore((state) => state.value);
    

    Когда выбирать Redux Toolkit

    • Крупное enterprise-приложение с большой командой
    • Нужны мощные DevTools для отладки и time-travel debugging
    • Сложная бизнес-логика с множеством взаимозависимых состояний
    • Уже используете RTK Query для управления серверным состоянием
    • Требуется строгая архитектура и единые соглашения в команде

    Когда выбирать Zustand

    • Небольшие или средние проекты
    • Нужно быстро стартовать без boilerplate-кода
    • Небольшая команда или соло-разработка
    • Хотите минимальный бандл (Zustand весит около 1 КБ)
    • Нужно локальное состояние нескольких компонентов без глобального store

    Частые ошибки

    Ошибка 1: Подписка на весь store в Zustand

    // Плохо: компонент перерендерится при любом изменении store
    const store = useCounterStore();
    
    // Хорошо: подписываемся только на нужное поле
    const value = useCounterStore((state) => state.value);
    

    Ошибка 2: Мутация состояния в Redux напрямую

    // Плохо: прямая мутация вне Immer-контекста вызовет ошибки
    const badReducer = (state, action) => {
      state.items.push(action.payload); // ошибка вне createSlice
      return state;
    };
    
    // Хорошо: используем createSlice — Immer встроен
    const goodSlice = createSlice({
      name: 'items',
      initialState: { items: [] },
      reducers: {
        addItem: (state, action) => {
          state.items.push(action.payload); // безопасно внутри createSlice
        },
      },
    });
    

    Ошибка 3: Хранить серверные данные в Zustand вместо React Query

    Zustand предназначен для клиентского состояния (UI, фильтры, модалки). Для серверных данных лучше использовать React Query или RTK Query — они берут на себя кэширование, дедупликацию запросов и инвалидацию.

    Ошибка 4: Один огромный store в Zustand

    // Плохо: всё в одном store — сложно поддерживать
    const useAppStore = create(() => ({
      user: null,
      cart: [],
      theme: 'dark',
      notifications: [],
    }));
    
    // Хорошо: разделяем по доменам
    const useUserStore = create(...);
    const useCartStore = create(...);
    const useThemeStore = create(...);
    

    Заключение

    Zustand и Redux Toolkit — отличные инструменты, каждый со своей нишей. Zustand побеждает в простоте, скорости разработки и размере бандла. Redux Toolkit — в структурированности, экосистеме и инструментах отладки.

    Для большинства новых проектов мы рекомендуем начинать с Zustand и переходить на RTK только тогда, когда сложность приложения этого действительно требует. Помните: лучший инструмент — тот, который решает вашу конкретную задачу с минимальными накладными расходами.

    Иконка глаза13

    Комментарии

    0

    Постройте личный план изучения Angular до уровня Middle — бесплатно!

    Angular — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

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

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

    Основы разработки

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    бесплатно
    Подробнее
    изображение курса

    Основы Git

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

    HTML и CSS

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

    Похожие статьи

    Картинка поста Kubernetes для разработчиков: деплой без знания DevOps
    Иконка аватараАнтон
    Иконка календаря25 апреля 2026
    KubernetesDevOpsDocker+ 3middleИконка уровня middle

    Kubernetes для разработчиков: деплой без знания DevOps

    Kubernetes для разработчиков: как задеплоить приложение в k8s без глубоких знаний DevOps — пошаговый разбор с примерами манифестов.

    Иконка чипа0
    Иконка глаза63
    Иконка комментариев0
    Картинка поста Redis на практике: кеширование, очереди и pub/sub для вашего бэкенда
    Иконка аватараАнтон
    Иконка календаря20 апреля 2026
    nodejsdockerapimiddleИконка уровня middle

    Redis на практике: кеширование, очереди и pub/sub для вашего бэкенда

    Redis на практике: разбираем кеширование с TTL и инвалидацией, очереди сообщений через BullMQ и pub/sub для уведомлений в реальном времени. Готовые примеры на Node.js и TypeScript.

    Иконка чипа0
    Иконка глаза243
    Иконка комментариев0
    Картинка поста PostgreSQL для разработчика: индексы, EXPLAIN и оптимизация запросов без DBA
    Иконка аватараАнтон
    Иконка календаря19 апреля 2026
    nodejspythonapimiddleИконка уровня middle

    PostgreSQL для разработчика: индексы, EXPLAIN и оптимизация запросов без DBA

    Разбираем оптимизацию запросов в PostgreSQL для разработчиков: индексы B-tree, чтение EXPLAIN ANALYZE, составные и частичные индексы, pg_stat_statements и практические приемы ускорения SQL-запросов без помощи DBA.

    Иконка чипа0
    Иконка глаза287
    Иконка комментариев0
    Иконка чипа0