Как я выбираю, где хранить состояние в React-приложении

В React можно запихнуть всё в один глобальный стор и жить в Redux. А можно утонуть в пропсах и коллбэках. Я стараюсь выбирать инструмент под задачу: от локального useState до Zustand/Redux, но с понятными границами.

Расскажу, как я обычно раскладываю состояние в проектах.

1. Сначала думаю про «радиус» состояния

Я задаю один простой вопрос: кому это состояние нужно?

  • Нужно только одному компоненту Беру useState/useReducer локально.

  • Нужно дереву внутри страницы Думаю про контекст или композицию через props.

  • Нужно по всему приложению Тогда уже смотрю в Zustand/Redux/MobX и т.п.

Ошибка, которую вижу часто: глобальный стор заводят «на всякий случай» и тащат туда даже состояние модалки.

2. Локальное состояние: базовый кирпич

Для форм, модалок, вкладок мне почти всегда хватает:

const [isOpen, setIsOpen] = useState(false);

const toggle = () => setIsOpen(prev => !prev);

Если логика сложнее (много полей, несколько действий), использую useReducer:

type State = { step: number; data: FormData }; type Action = { type: 'NEXT' } | { type: 'SET_DATA'; payload: FormData };

function reducer(state: State, action: Action): State { switch (action.type) { case 'NEXT': return { ...state, step: state.step + 1 }; case 'SET_DATA': return { ...state, data: action.payload }; } }

Локальный стейт проще тестировать и не требует внешних зависимостей.

3. Контекст: только для «сквозных» вещей

Я использую React.createContext для:

  • текущего пользователя
  • темы/настроек интерфейса
  • текущего языка, токенов фич-флагов

Важно не превращать один контекст в «свалку всего», иначе любое изменение перерендерит полприложения.

4. Глобальный стор: когда без него уже больно

Я подключаю Zustand/Redux, когда:

  • много сущностей (users, orders, products)
  • данные переиспользуются на разных страницах
  • нужны кэширование запросов, нормальные эффекты, девтулы

Главное правило: в сторе храним данные домена, а не локальное состояние UI вроде «открыта ли эта конкретная модалка».

5. React Query / SWR: стейт запросов, а не бизнес-логики

Отдельная категория — загрузка данных. Для этого я всё чаще использую React Query:

  • кеширует ответы
  • даёт статус загрузки/ошибок
  • поддерживает рефетч, инвалидацию

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

6. Как я раскладываю состояние по слоям

Обычно придерживаюсь такой схемы:

  • локальный стейт для UI-мелочей (открытие модалки, активная вкладка, значения формы до сабмита)

  • контекст для сквозных вещей (тема, язык, авторизация)

  • React Query для данных, которые приходят из API

  • Zustand/Redux только когда есть сложная доменная логика, кэш, вычисляемые селекторы

Так приложение получается читаемым: открываешь файл и понимаешь, каких уровней состояния он касается.

Чек-лист перед тем, как заводить глобальный стор

  • Понимаю, какие данные реально нужны на нескольких страницах
  • Попробовал решить задачу локальным стейтом и/или контекстом
  • Для данных с API уже использую React Query / SWR, не дублирую кэш руками
  • Есть чёткое разделение: доменные данные в сторе, UI-мелочи в компонентах
  • Понимаю, кто будет поддерживать эту архитектуру в команде

Итог

Управление состоянием в React — это не выбор «Redux или нет», а расстановка границ: что живёт в компоненте, что в контексте, а что в отдельном сторе. Если не тащить всё в глобальный стейт и использовать специальные инструменты для запросов, проект остаётся предсказуемым, а добавление новых фич не превращается в борьбу с бесконечными пропсами и перерендерами.

#reactjs #javascript #frontend

Как я выбираю, где хранить состояние в React-приложении
В React можно запихнуть всё в один глобальный стор и жить в Redux. А можно утонуть в пропсах и коллбэках | Сетка — социальная сеть от hh.ru