React Context

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Всем привет! Меня зовут Андрей, я Frontend разработчик. На данный момент работаю на фрилансе. Имею достаточно хороший опыт работы с React.

Хочу рассказать, что такое React Context и как это можно использовать в проектах.
Попробую всё рассказать как можно проще.

Начнем

React context - некий интерфейс, который позволяет сохранять какие-либо данные и передавать их вниз по дереву без передачи пропсов в дочерние компоненты.

Т.е по сути что-то на подобие стора из всем нам известных Redux, MobX, Effector и т.п, но конечно же есть различия и довольно большой минус, о котором мы поговорим ниже, после просмотра примеров кода.

Немного о том, какие методы и компоненты используются в Context.

createContext - объявление контекста (можете воспринимать это как store из redux для большего начального понимания).

Context.Provider - компонент, оборачивающий наши компоненты, которые должны иметь доступ к данным.

useContext - хук, позволяющий получить данные из context.

В целом всё достаточно просто.

Теперь разберём пример, чтобы закрепить понимание.

Допустим нам нужно реализовать смену темы в приложении. Вот как это можно сделать:

import { FC, createContext, useContext, useState, ReactNode } from 'react';

type Theme = 'light' | 'dark';

interface ThemeContextType {
  theme: Theme;
  toggleTheme: () => void;
}

export const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export const ThemeProvider: FC<{ children: ReactNode }> = ({ children }) => {
  const [theme, setTheme] = useState<Theme>('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

Как видно из примера, мы создаем context с помощью createContext. В качестве первого параметра указываем начальное значение - undefined. Конечно же там может быть всё что угодно: массив, объект, строка, число и т.д. Через джинерик указываем тип ThemeContextType | undefined.

Далее создаем провайдер - ThemeProvider ( обычный компонент с children, но обернутый в Context.Provider. В value передаем данные, которые будут доступны всем дочерним компонентам.

Теперь перейдем к тому как использовать объявленный context.

Допустим мы хотим дать доступ к этим данным для всех компонентов. Рационально это сделать в каком нибудь layout компоненте:

export const Layout = () => {
  return(
    <ThemeProvider>
      <Header />
      <MainContent />
      <Footer />
    </ThemeProvider>
  )
}

Теперь для Header, MainContent, Footer и всем их дочерним компонентам будут доступны theme и toggleTheme из контекста.
Т.е провайдер мы можем, например, использовать и только для MainContent. И тогда theme, toggleTheme будут доступны только для дочерних компонентов MainContent.

В этом примере показываю как юзать данные из контекста:

import {useContext} from "react";
import {ThemeContext} from "какой-то путь"

export const Header = () => {
  const {theme, toggleTheme} = useContext(ThemeContext)
  
  return(
    <div>
      <p>Сейчас включена тема: {theme === 'light' ? "Светлая" : "Тёмная"}</p>
      <button onClick={toggleTheme}>Изменить тему</button>
    </div>
  )
}

В useContext передаем переменную в которой объявили createContext()

В React 19 теперь можем вместо useContext юзать use(), а use использовать в условиях. Круто, правда? Конечно круто)

И так, конечно всё это очень прикольно и интересно, но Context имеет довольно большой минус:

Все, что использует контекст, перерендеривается каждый раз, когда контекст изменяет состояние.
Только компоненты, которые вызывают useContext, повторно ререндерятся при изменении стейта контекста.


Но это не значит, что использовать context не нужно. Нужно. Просто аккуратно и отслеживая производительность. Часто я использовал context в проектах не замечая каких-либо падений производительности вообще.

Вот как раз этот минус закрывается при использовании Redux и MobX. Но у Вас может возникнуть вопрос: "Как же нам помогают эти либы, если они тоже используют Context из React ?".

Вот так:

Хранилище, которое разделяют эти библиотеки управления состоянием с контекстом, немного отличается от совместного использования состояния непосредственно с контекстом. Когда вы используете Redux и Mobx, работает алгоритм сравнения, который обеспечивает повторный рендеринг только тех компонентов, которые действительно необходимы для визуализации.

Подведу небольшой итог

React Context — это удобный инструмент для управления состоянием, который позволяет передавать данные через дерево компонентов без использования пропсов. Он прост в использовании, но требует внимательного подхода из-за особенностей с перерендером компонентов при изменении состояния.

Кому интересно, веду блог в telegram - https://t.me/budn1_codera

Источник: https://habr.com/ru/articles/873044/


Интересные статьи

Интересные статьи

Интернет-магазины и площадки электронной коммерции — это сложные системы, в работе которых могут случаться сбои и ошибки. Но в коммерческой среде простои в работе — это всегда убытки. В статье расскаж...
Представляю вашему вниманию цикл статей по работе с пока еще мало знакомым многим битрикс-разработчикам инструментом оперирования данными с CRM Битрикс24 через абстрактные фабрики. В первой статье рас...
Задача - сделать AMP версию всего сайта на 1С-Битрикс, чтобы содержание AMP страниц всегда соответствовало оригинальным и изменялось при изменении оригинальных.
Особенность архитектуры 1С-Битрикс предполагает наличие контента как в базе (например: инфоблоки), так и непосредственно в статических файлах проекта.Данный формат создавал проблемы при совместной р...
В этом материале мы покажем, что Интернет вещей — это не так уж и сложно. Для этого за 60 минут соберем и оживим простейшую Wi-Fi розетку с управлением через Интернет. Читат...