В React, данные передаются внутрь компонентов через пропсы с верхних уровней на нижние. Но иногда такой подход неудобен, при работе с глобальными данными, которые нужны одновременно во многих компонентах на разных уровнях иерархии. К таким данным относится текущий уровень, текущая тема (темная или светлая и т.п.). Напрямую передавать такие данные неудобно, придется протаскивать их сквозь все приложение. Для таких случаев в React добавили механизм контекстов. Он позволяет передать в приложение и получить внутри любого компонента доступ к данным напрямую, минуя пропсы.
Хук useContext()
позволяет использовать контекст внутри компонента. Для этого нужно выполнить три действия:
Инициализировать контекст в том же месте, где инициализируется приложение
// Параметром передается значение по умолчанию
// Имя контекста выбирается произвольно
const UserContext = React.createContext({});
Подключить провайдер и передать данные в контекст через пропс value
.
// user – данные которые лежат внутри контекста
<UserContext.Provider value={user}>
<MyComponent />
</UserContext.Provider>
Получить данные контекста
import React, { useContext } from 'react';
const MyComponent = () => {
// Возвращает контекст целиком
const user = useContext(UserContext);
return <h1>{user.name}</h1>;
}
Вот другой пример контекста, в котором хранится текущая тема:
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
const ThemeContext = React.createContext(
themes.dark, // значение по умолчанию
);
И где-то внутри приложения:
<ThemeContext.Provider value={/* текущая тема */}>
<Content />
</ThemeContext.Provider>
Внутри контекста может храниться как примитивное значение, так и объект. Изменение содержимого такого объекта никак не отслеживается React, поэтому не приводит к перерендеру. Но если заменить сам объект, то из-за изменившейся ссылки React узнает об изменении и выполнит перерисовку компонентов внутри провайдера.
Иногда возникает ситуация, когда в контексте нужно хранить динамические данные. Например, при авторизации. Когда пользователь авторизован, мы должны сохранить какие-то данные, чтобы пользователю предоставлялись дополнительные функции. Сам по себе контекст для этого ничего не предоставляет, но можно передать в контекст методы для манипулирования данными, а сами данные хранить с помощью useState()
. Более продвинутый вариант — это создать провайдер в отдельном компоненте. Так мы сможем изолировать данные от всего приложения, а в компоненты передавать интерфейс для взаимодействия с данными.
Для этого создадим контекст в отдельном модуле, чтобы все компоненты могли его импортировать:
// ThemeContext.js
import { createContext } from 'react';
export default createContext({
themes: {},
theme: {},
setTheme: () => {},
});
Создаем отдельный компонент провайдера:
import ThemeContext from './ThemeContext.js';
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee',
},
dark: {
foreground: '#ffffff',
background: '#222222',
},
};
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState(themes.dark);
const setLightTheme = () => setTheme(themes.light);
const setDarkTheme = () => setTheme(themes.dark);
return (
<ThemeContext.Provider value={{ theme, setLightTheme, setDarkTheme, themes }}>
{children}
</ThemeContext.Provider>
);
};
И внутри приложения используем провайдер как обычный компонент:
<ThemeProvider>
<MyComponent />
</ThemeProvider>
В самом компоненте теперь можно импортировать контекст и использовать функции из провайдера для изменения состояния в контексте:
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext.js';
const MyComponent = () => {
const { setLightTheme } = useContext(ThemeContext);
return <button onClick={() => setLightTheme()}>Включить светлую тему</button>;
}
Контекст - удобный механизм для некоторых особых ситуаций, но он не должен становиться основным способом передачи данных внутрь приложения. Такой соблазн появляется у многих, кто использует его впервые. Главная проблема контекстов – связывание компонентов с глобальными данными, а это затрудняет их повторное использование в других ситуациях.
Вам ответят команда поддержки Хекслета или другие студенты.
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.
Зарегистрируйтесь или войдите в свой аккаунт