> Где хранить состояние в React (React)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: IT-One, Сбер, SmartWay
Стек: React
> Пример ответа
Короткий ответ
Состояние в React хранится в зависимости от его природы и области видимости: локальное - в useState или useReducer внутри компонента, глобальное - в контексте (React.createContext) или внешних стейт-менеджерах (Redux, Zustand, MobX). Для серверных данных - в React Query, SWR или RTK Query. Кэш URL (search params) - для фильтров и пагинации. Выбор диктуется trade-off между производительностью, сложностью синхронизации и масштабируемостью.
Подробное объяснение
Состояние в React делится на несколько категорий, каждая со своим местом хранения:
-
Локальное состояние - данные, принадлежащие одному компоненту или его потомкам. Хранится в
useStateдля простых значений,useReducerдля сложной логики обновления. Пример: значение инпута, состояние модалки. -
Глобальное состояние - данные, доступные многим компонентам на разных уровнях дерева. Используется
React.createContext+useContextдля простых кейсов (тема, авторизация). Для сложных приложений - Redux (средствами Redux Toolkit), Zustand (минималистичный API), MobX (реактивное программирование). Выбор зависит от требований к traceability, middleware и размера команды. -
Серверное состояние - данные с бэкенда. Хранить в глобальном стейте - антипаттерн, так как требует ручной синхронизации с кэшем и инвалидации. Лучше использовать библиотеки: React Query (TanStack Query), SWR или RTK Query. Они автоматически управляют кэшированием, refetching, optimistic updates.
-
URL/роутер - состояние, влияющее на навигацию: фильтры, пагинация, поисковые запросы. Хранится в search params (через
useSearchParamsиз React Router или Next.js). Это позволяет делиться ссылками и поддерживать back/forward. -
Формы - сложное состояние с валидацией. Лучше выносить в библиотеки (React Hook Form, Formik), которые оптимизируют ререндеры и управляют полями.
-
Кэш вычислений - мемоизированные значения через
useMemoили библиотеки вроде Reselect для селекторов.
Правило: состояние должно быть как можно ближе к месту использования. Поднимать его вверх только при необходимости разделить между компонентами. Избегать хранения производных данных (вычисляемых из других состояний) - использовать useMemo.
На практике
- Для простого приложения (до 5-10 компонентов) достаточно
useState+useContextдля темы/авторизации. - Для среднего приложения (с серверными данными) - React Query + локальный стейт в компонентах.
- Для крупного enterprise (много бизнес-логики, middleware, сложные side effects) - Redux Toolkit (с RTK Query) или Zustand + React Query.
- Для форм - React Hook Form, состояние формы не хранить в Redux.
- Для фильтров/пагинации - URL search params, синхронизировать с React Query через
keepPreviousData. - Избегать хранения в Redux того, что можно получить из контекста или URL.
Пример кода
JSX// Локальное состояниеconst [input, setInput] = useState('');// Глобальное через контекстconst ThemeContext = createContext('light');function App() {const [theme, setTheme] = useState('light');return (<ThemeContext.Provider value={{ theme, setTheme }}><Main /></ThemeContext.Provider>);}// Серверное состояние через React Queryfunction Users() {const { data, isLoading } = useQuery({queryKey: ['users'],queryFn: fetchUsers,});return isLoading ? <Spinner /> : <UserList users={data} />;}// URL состояниеfunction Filters() {const [searchParams, setSearchParams] = useSearchParams();const filter = searchParams.get('status') || 'all';return (<select value={filter} onChange={e => setSearchParams({ status: e.target.value })}><option value="all">All</option><option value="active">Active</option></select>);}
Как отвечать на собеседовании
Начни с классификации состояний, затем объясни критерии выбора: область видимости, источник данных (локальный/серверный), частота изменений, необходимость синхронизации между вкладками. Приведи конкретные примеры из практики, где выбор хранилища повлиял на производительность или поддерживаемость. Упомяни антипаттерны: хранение computed значений, дублирование состояния в нескольких местах, помещение всего в Redux. Будь готов обсудить trade-off между Context (ререндеры всех потребителей) и Redux (селекторы, мемоизация).
Что проверяет интервьюер
- Понимание иерархии состояний и принципа single source of truth.
- Умение выбирать инструмент под задачу, а не по привычке.
- Знание проблем производительности (ререндеры, лишние вычисления).
- Опыт работы с серверным состоянием и кэшированием.
- Понимание разницы между UI-состоянием и бизнес-логикой.
Типичные ошибки
- Хранение всего в Redux, включая временные UI-состояния (инпуты, модалки).
- Использование Context для часто обновляемых данных (приводит к массовым ререндерам).
- Хранение серверных данных в глобальном стейте без кэша и инвалидации.
- Дублирование состояния (например, копия данных из Redux в локальный стейт).
- Хранение computed значений (например,
fullName = firstName + lastName) - использоватьuseMemo. - Игнорирование URL как источника состояния для фильтров.
> Похожие задачи по frontend
Как реализовать shouldComponentUpdate в React
Использовал ли ты Zustand
Что такое JSX в React и зачем он нужен
В чем особенность портала (React Portal) и почему его нужно использовать
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью