8. useContext
`useContext` - это хук в React, который позволяет получать доступ к значениям контекста в функциональных компонентах. Он помогает избежать прокидывания пропсов через множество промежуточных компонентов, упрощая структуру приложения.
## Концепция useContext
Представьте, что у вас есть глобальная переменная, к которой должны иметь доступ многие компоненты в вашем приложении. Вместо того, чтобы передавать эту переменную как пропс каждому компоненту по цепочке, вы можете использовать `useContext`. Context позволяет предоставить некоторое значение всем компонентам, находящимся в его дереве.
### Создание контекста
Сначала нужно создать контекст с помощью `React.createContext()`.
```javascriptimport React from 'react';
const ThemeContext = React.createContext('light'); // 'light' - значение по умолчаниюПровайдер контекста
Заголовок раздела «Провайдер контекста»Затем нужно предоставить значение контекста с помощью ThemeContext.Provider. Все компоненты, находящиеся внутри ThemeContext.Provider, смогут получить доступ к значению контекста.
import React from 'react';import ThemeContext from './ThemeContext'; // Предполагаем, что ThemeContext находится в отдельном файле
function App() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> );}Использование useContext
Заголовок раздела «Использование useContext»Внутри дочерних компонентов можно использовать хук useContext для получения доступа к значению контекста.
import React, { useContext } from 'react';import ThemeContext from './ThemeContext';
function Toolbar() { return ( <div> <ThemedButton /> </div> );}
function ThemedButton() { const theme = useContext(ThemeContext);
return ( <button style={{ backgroundColor: theme === 'dark' ? 'black' : 'white', color: theme === 'dark' ? 'white' : 'black' }}> Я кнопка с темой: {theme} </button> );}Практические примеры кода
Заголовок раздела «Практические примеры кода»Пример 1: Передача данных пользователя
import React, { createContext, useContext, useState } from 'react';
const UserContext = createContext(null);
function UserProvider({ children }) { const [user, setUser] = useState({ name: 'Guest', isLoggedIn: false });
return ( <UserContext.Provider value={{ user, setUser }}> {children} </UserContext.Provider> );}
function Profile() { const { user } = useContext(UserContext);
return ( <div> {user.isLoggedIn ? `Welcome, ${user.name}!` : 'Please log in.'} </div> );}
function LoginButton() { const { setUser } = useContext(UserContext);
const handleLogin = () => { setUser({ name: 'John Doe', isLoggedIn: true }); };
return <button onClick={handleLogin}>Login</button>;}
function App() { return ( <UserProvider> <Profile /> <LoginButton /> </UserProvider> );}
export default App;Пример 2: Управление темой приложения
(Этот пример расширяет пример выше, показывая переключение темы)
import React, { createContext } from 'react';
const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {} });
export default ThemeContext;
// App.jsimport React, { useState } from 'react';import ThemeContext from './ThemeContext';import ThemedComponent from './ThemedComponent';
function App() { const [theme, setTheme] = useState('light');
const toggleTheme = () => { setTheme(theme === 'light' ? 'dark' : 'light'); };
return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <ThemedComponent /> </ThemeContext.Provider> );}
export default App;
// ThemedComponent.jsimport React, { useContext } from 'react';import ThemeContext from './ThemeContext';
function ThemedComponent() { const { theme, toggleTheme } = useContext(ThemeContext);
return ( <div style={{ backgroundColor: theme === 'light' ? 'white' : 'black', color: theme === 'light' ? 'black' : 'white' }}> <h1>Themed Component</h1> <button onClick={toggleTheme}>Toggle Theme</button> </div> );}
export default ThemedComponent;Жизненный пример
Заголовок раздела «Жизненный пример»useContext широко используется в реальных проектах для управления глобальным состоянием и конфигурацией.
- Redux/MobX: Эти библиотеки управления состоянием часто используют Context API React под капотом для предоставления доступа к хранилищу данных компонентам.
- Тематизация (Material UI, Ant Design): Фреймворки UI-компонентов используют Context API для передачи темы приложения (цвета, шрифты и т.д.) всем компонентам, обеспечивая консистентный внешний вид.
- Аутентификация: Context часто используется для хранения информации о текущем пользователе и его статусе аутентификации, что позволяет легко контролировать доступ к различным частям приложения.
- Next.js/Gatsby: При работе с этими фреймворками, useContext может быть использован для передачи данных, полученных на сервере, в компоненты на клиенте.
Ключевые моменты
Заголовок раздела «Ключевые моменты»useContextупрощает доступ к глобальным данным, избегая прокидывания пропсов.React.createContext()создает новый контекст.Context.Providerпредоставляет значение контекста для дочерних компонентов.useContext(Context)позволяет получить доступ к значению контекста внутри функционального компонента.- Context полезен для управления темами, аутентификацией и другими глобальными настройками приложения.
## Интерактивный пример
<Playground client:load template="react" files={{ "/App.tsx": `import React, { useState, useContext, createContext } from 'react';
// 1. Создаем контекстconst ThemeContext = createContext('light');
// 2. Дочерний компонент, потребляющий контекстfunction ThemedBox() { // Получаем текущее значение контекста напрямую const theme = useContext(ThemeContext); const isDark = theme === 'dark';
return ( <div style={{ padding: '20px', marginTop: '15px', borderRadius: '8px', backgroundColor: isDark ? '#282c34' : '#eee', color: isDark ? 'white' : '#333', transition: 'all 0.2s' }}> <p>Значение из контекста: <b>{theme}</b></p> <p>Пропсы не использовались!</p> </div> );}
// 3. Родительский компонент с провайдеромexport default function App() { const [theme, setTheme] = useState('dark');
return ( <ThemeContext.Provider value={theme}> <div style={{ padding: '20px', fontFamily: 'sans-serif' }}> <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')} style={{ padding: '8px 12px', cursor: 'pointer' }} > Сменить тему </button>
{/* Компонент внутри Provider имеет доступ к контексту */} <ThemedBox /> </div> </ThemeContext.Provider> );}` }} />