← Назад к вопросам

В чем разница между стейт-менеджером и контекстом?

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 APIState 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

Выбор инструмента:

  1. Начни с useState + props (простое состояние)
  2. Если нужно избежать prop drilling -> Context
  3. Если состояние сложное и часто меняется -> State Manager
  4. Для асинхронности -> State Manager или TanStack Query
  5. Для модальных окон и уведомлений -> Context или простой Store