Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як створити глобальний стан з useContext?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`useContext`** дозволяє створити "глобальний контейнер" даних через `Context`, дати доступ до цих даних будь-якому компоненту в дереві без передавання пропсів "вниз по ланцюжку" (`prop drilling`). **Ключове:** для цього спершу створюють контекст через `createContext`, потім провайдер зі станом, а вже потім будь-який компонент читає й змінює цей стан через `useContext(Context)`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що робить `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`) |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.