Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Хук useContext JS: React Hooks

В React, данные передаются внутрь компонентов через пропсы с верхних уровней на нижние. Но иногда такой подход неудобен, при работе с глобальными данными, которые нужны одновременно во многих компонентах на разных уровнях иерархии. К таким данным относится текущий уровень, текущая тема (темная или светлая и т.п.). Напрямую передавать такие данные неудобно, придется протаскивать их сквозь все приложение. Для таких случаев в React добавили механизм контекстов. Он позволяет передать в приложение и получить внутри любого компонента доступ к данным напрямую, минуя пропсы.

Хук useContext() позволяет использовать контекст внутри компонента. Для этого нужно выполнить три действия:

  1. Инициализировать контекст в том же месте, где инициализируется приложение

    // Параметром передается значение по умолчанию
    // Имя контекста выбирается произвольно
    const UserContext = React.createContext({});
    
  2. Подключить провайдер и передать данные в контекст через пропс value.

    // user – данные которые лежат внутри контекста
    <UserContext.Provider value={user}>
      <MyComponent />
    </UserContext.Provider>
    
  3. Получить данные контекста

    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>;
}

Контекст - удобный механизм для некоторых особых ситуаций, но он не должен становиться основным способом передачи данных внутрь приложения. Такой соблазн появляется у многих, кто использует его впервые. Главная проблема контекстов – связывание компонентов с глобальными данными, а это затрудняет их повторное использование в других ситуациях.


Дополнительные материалы

  1. Использование хука useContext
  2. Механизм контекстов

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
с нуля
Разработка фронтенд-компонентов для веб-приложений
2 февраля 10 месяцев
Иконка программы Онлайн-буткемп. Фронтенд-разработчик
Профессия
Новый с нуля
Интенсивное обучение профессии в режиме полного дня
9 февраля 4 месяца
Иконка программы Fullstack-разработчик
Профессия
с нуля
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
2 февраля 16 месяцев

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»