← Назад к вопросам
В чем разница между стейт-менеджером и контекстом?
1.7 Middle🔥 182 комментариев
#React#State Management
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между стейт-менеджером и контекстом?
Что такое Context
Context в React - встроенный механизм для передачи данных вниз по дереву компонентов, минуя prop drilling (передача через цепочку компонентов).
// Создание контекста
const ThemeContext = createContext<'light' | 'dark'>('light');
// Провайдер
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
}
// Использование
const Component = () => {
const theme = useContext(ThemeContext);
return <div className={theme}>Content</div>;
};
Что такое State Manager
State Manager (Redux, Zustand, MobX) - это библиотека для управления глобальным состоянием приложения с централизованным хранилищем, преднамеренными обновлениями и dev-tools.
// Zustand пример
const useStore = create((set) => ({
theme: 'light',
toggleTheme: () => set((state) => ({
theme: state.theme === 'light' ? 'dark' : 'light'
}))
}));
// Redux пример
const themeSlice = createSlice({
name: 'theme',
initialState: { value: 'light' },
reducers: {
toggleTheme: (state) => {
state.value = state.value === 'light' ? 'dark' : 'light';
}
}
});
Ключевые отличия
Таблица сравнения:
| Аспект | Context API | State Manager (Redux/Zustand) |
|---|---|---|
| Встроен в React | Да | Нет (отдельная библиотека) |
| Производительность | Ниже (перерендер всех потребителей) | Выше (оптимизированные подписки) |
| Dev Tools | Нет | Да (Redux DevTools и т.п.) |
| Scalability | Для небольших приложений | Для больших приложений |
| Boilerplate | Минимум | Больше кода |
| Middleware | Нет | Да (логирование, асинхронность) |
| Time Travel Debugging | Нет | Да (в Redux) |
| Сложность | Простая | Более сложная |
Проблема Context API - производительность
Проблема: Все потребители перерендариваются при изменении значения
const ThemeContext = createContext(null);
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState(null);
const value = { theme, user, setTheme, setUser };
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
// Даже если компонент использует только theme,
// он перерендарится при изменении user!
function Header() {
const { theme } = useContext(ThemeContext);
console.log('Header перерендарился');
return <header className={theme}>...</header>;
}
function UserCard() {
const { user } = useContext(ThemeContext);
console.log('UserCard перерендарился');
return <div>{user.name}</div>;
}
При setUser() вызывается:
- Header перерендарится (хотя user не использует)
- UserCard перерендарится
Решение: Разделить контексты
const ThemeContext = createContext('light');
const UserContext = createContext(null);
const ThemeDispatchContext = createContext(null);
function App() {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState(null);
return (
<ThemeContext.Provider value={theme}>
<ThemeDispatchContext.Provider value={setTheme}>
<UserContext.Provider value={user}>
{children}
</UserContext.Provider>
</ThemeDispatchContext.Provider>
</ThemeContext.Provider>
);
}
Когда использовать Context
1. Простое состояние (тема, язык)
// Идеально для Context - небольшое, редко меняется
const LanguageContext = createContext('en');
function LanguageProvider({ children }) {
const [language, setLanguage] = useState('en');
return (
<LanguageContext.Provider value={language}>
{children}
</LanguageContext.Provider>
);
}
2. Данные для авторизации
const AuthContext = createContext<User | null>(null);
function AuthProvider({ children }) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
// Загрузить пользователя
fetchCurrentUser().then(setUser);
}, []);
return (
<AuthContext.Provider value={user}>
{children}
</AuthContext.Provider>
);
}
Когда использовать State Manager
1. Сложное состояние (магазин)
// Redux для e-commerce
const initialState = {
products: [],
cart: [],
filters: { category: '', price: 0 },
isLoading: false,
error: null
};
const slice = createSlice({
name: 'shop',
initialState,
reducers: {
addToCart: (state, action) => {
state.cart.push(action.payload);
},
removeFromCart: (state, action) => {
state.cart = state.cart.filter(item => item.id !== action.payload);
},
setFilters: (state, action) => {
state.filters = action.payload;
}
}
});
2. Асинхронные операции
// Redux Thunk или Zustand async
const useStore = create((set) => ({
data: [],
isLoading: false,
fetchData: async () => {
set({ isLoading: true });
try {
const data = await fetch('/api/data').then(r => r.json());
set({ data, isLoading: false });
} catch (error) {
set({ isLoading: false });
}
}
}));
3. DevTools и отладка
// Redux DevTools помогает отладить состояние
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(logger)
});
// Видно все действия и состояние
Гибридный подход
// Context для пропса (избегаем prop drilling)
const AuthContext = createContext(null);
// State Manager для сложного состояния
const useStore = create((set) => ({
// Глобальное состояние приложения
}));
function App() {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={user}>
<Component /> {/* Может использовать Context или Store */}
</AuthContext.Provider>
);
}
Практические примеры
Пример 1: Context для модальных окон
const ModalContext = createContext<ModalContextType | null>(null);
function ModalProvider({ children }) {
const [modal, setModal] = useState<Modal | null>(null);
const openModal = (type: string, data?: any) => {
setModal({ type, data });
};
const closeModal = () => {
setModal(null);
};
return (
<ModalContext.Provider value={{ modal, openModal, closeModal }}>
{children}
{modal && <Modal type={modal.type} data={modal.data} />}
</ModalContext.Provider>
);
}
Пример 2: Zustand для состояния фильтров
const useFiltersStore = create((set) => ({
filters: {
search: '',
category: null,
priceFrom: 0,
priceTo: 1000
},
setSearch: (search: string) =>
set((state) => ({
filters: { ...state.filters, search }
})),
setCategory: (category: string | null) =>
set((state) => ({
filters: { ...state.filters, category }
})),
reset: () =>
set({
filters: {
search: '',
category: null,
priceFrom: 0,
priceTo: 1000
}
})
}));
function FilterPanel() {
const { filters, setSearch, setCategory } = useFiltersStore();
return (
<div>
<input value={filters.search} onChange={(e) => setSearch(e.target.value)} />
<select value={filters.category} onChange={(e) => setCategory(e.target.value)}>
{/* options */}
</select>
</div>
);
}
Современный рекомендуемый подход
// Context для провайдеров данных (AuthProvider, ThemeProvider)
// Zustand или Recoil для UI состояния (фильтры, модальные окна)
// App.tsx
function App() {
return (
<AuthProvider>
<ThemeProvider>
<Layout />
</ThemeProvider>
</AuthProvider>
);
}
// Компонент
function ProductList() {
// Глобальное состояние из Zustand
const filters = useFiltersStore((state) => state.filters);
// Контекст для данных пользователя
const user = useContext(AuthContext);
return <></> ;
}
Best Practices
Выбор инструмента:
- Начни с useState + props (простое состояние)
- Если нужно избежать prop drilling -> Context
- Если состояние сложное и часто меняется -> State Manager
- Для асинхронности -> State Manager или TanStack Query
- Для модальных окон и уведомлений -> Context или простой Store