Skip to main content

Як створити глобальний стан з useContext?

Що робить useContext

useContext дозволяє:

Створити "глобальний контейнер" даних (через Context) Дати доступ до цих даних будь-якому компоненту в дереві Без передавання пропсів "вниз по ланцюжку" (prop drilling)


1. Створи контекст

javascript
import { createContext } from "react"; // Створюємо контекст export const ThemeContext = createContext();

Контекст - це "коробка", у якій React зберігатиме дані. Пізніше ти "заллєш" туди стан і "розіллєш" по застосунку.


2. Створи провайдер (компонент, де зберігається стан)

javascript
import { useState, createContext } from "react"; // створюємо контекст export const ThemeContext = createContext(); export function ThemeProvider({ children }) { const [theme, setTheme] = useState("light"); const toggleTheme = () => setTheme((prev) => (prev === "light" ? "dark" : "light")); return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); }

Що відбувається:

  • Ми створили глобальний стан theme
  • Обгорнули його в <ThemeContext.Provider />
  • Передали у value те, чим хочемо ділитися (theme, toggleTheme)

Тепер усі дочірні компоненти всередині <ThemeProvider> зможуть отримувати доступ до цих даних.


3. Обгорни весь застосунок провайдером

У App.jsx або main.jsx:

javascript
import { ThemeProvider } from "./ThemeContext"; import Page from "./Page"; function App() { return ( <ThemeProvider> <Page /> </ThemeProvider> ); } export default App;

Тепер усі компоненти всередині ThemeProvider зможуть використовувати useContext(ThemeContext) і читати / змінювати глобальний стан.


4. Використай useContext у будь-якому компоненті

javascript
import { useContext } from "react"; import { ThemeContext } from "./ThemeContext"; function Header() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <header style={{ backgroundColor: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff", }} > <p>Поточна тема: {theme}</p> <button onClick={toggleTheme}>Змінити тему</button> </header> ); }

Усе! Компонент Header тепер отримує доступ до глобального стану теми, хоча він зберігається "вгорі" застосунку, без передавання через пропси.


Як це працює під капотом

  1. createContext() створює "канал зв'язку" між компонентами.
  2. <Provider value={...}> робить дані доступними для всіх нащадків.
  3. useContext(Context) підписує компонент на оновлення цього контексту. → Якщо value у провайдері змінюється, React перемалює всіх підписників.

Важливо: useContext не панацея

Хоча Context = "глобальний стан", використовувати його потрібно обережно:

ПроблемаОпис
Усі підписники ререндерятьсяПри кожній зміні значення у Provider
Не підходить для дуже часто змінюваних данихНаприклад, лічильник FPS або курсор миші
Краще підходить для "налаштувань"Тема, мова, поточний користувач, авторизація

Для часто оновлюваних даних краще використовувати Zustand, Jotai, Redux, або розділяти контексти (щоб кожен містив лише одну частину стану).


Повний приклад структури проекту

javascript
src/ ├─ context/ │ └─ ThemeContext.jsx ├─ components/ │ ├─ Header.jsx │ └─ Footer.jsx ├─ App.jsx └─ main.jsx

ThemeContext.jsx

javascript
import { createContext, useState } from "react"; export const ThemeContext = createContext(); export function ThemeProvider({ children }) { const [theme, setTheme] = useState("light"); const toggleTheme = () => setTheme((prev) => (prev === "light" ? "dark" : "light")); return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); }

Header.jsx

javascript
import { useContext } from "react"; import { ThemeContext } from "../context/ThemeContext"; export function Header() { const { theme, toggleTheme } = useContext(ThemeContext); return ( <header className={theme}> <h1>Тема: {theme}</h1> <button onClick={toggleTheme}>Змінити</button> </header> ); }

App.jsx

javascript
import { ThemeProvider } from "./context/ThemeContext"; import { Header } from "./components/Header"; export default function App() { return ( <ThemeProvider> <Header /> </ThemeProvider> ); }

Підсумок

ПитанняВідповідь
Що робить useContext?Дозволяє читати дані з найближчого <Context.Provider>
Як створити глобальний стан?Обгорни стан у Context.Provider і використовуй useContext
Коли застосовувати?Коли дані потрібні в різних місцях дерева (тема, мова, користувач)
Чим замінити у складних випадках?Zustand, Redux, Jotai, Recoil та ін.
Як уникнути зайвих ререндерів?Розділяй контексти й мемоізуй value (через useMemo)

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.