createContext

createContext позволяет вам создать контекст, который можно предоставлять или читать.

const SomeContext = createContext(defaultValue)

Справочник

createContext(defaultValue)

Вызовите createContext вне кода компонентов для создания контекста.

import { createContext } from 'react';

const ThemeContext = createContext('light');

Больше примеров ниже.

Параметры

  • defaultValue: Значение контекста по умолчанию, когда над компонентом, читающим контекст, нет провайдера соответствующего контекста. Если у вас нет подходящего значения по умолчанию, используйте null. Значение по умолчанию используется как вариант “на крайний случай”. Оно постоянно и никогда не изменится с течением времени.

Возвращаемое значение

createContext возвращает объект контекста.

Объект контекста сам по себе не содержит никакой информации. Он говорит о том, какой контекст компоненты читают или предоставляют. Обычно, вы будете использовать SomeContext.Provider в компонентах выше, чтобы определить значение контекста, и вызывать useContext(SomeContext) в компонентах ниже, чтобы получить его значение. Объект контекста имеет несколько параметров:

  • SomeContext.Provider позволяет предоставить контекст компонентам.
  • SomeContext.Consumer альтернативный и редко используемый способ получить значение контекста.

SomeContext.Provider

Оберните ваши компоненты в провайдер контекста, чтобы определить его значение для всех компонентов внутри:

function App() {
const [theme, setTheme] = useState('light');
// ...
return (
<ThemeContext.Provider value={theme}>
<Page />
</ThemeContext.Provider>
);
}

Пропсы

  • value: Значение, которое вы хотите передать всем компонентам внутри данного провайдера, читающим этот контекст. Глубина вложенности не играет роли. Тип значения может быть любым. Компонент, вызывающий useContext(SomeContext) внутри провайдера, получает value ближайшего провайдера соответствующего контекста.

SomeContext.Consumer

Когда useContext ещё не существовал, был старый способ получить значение контекста:

function Button() {
// 🟡 Старый способ (не рекомендуется)
return (
<ThemeContext.Consumer>
{theme => (
<button className={theme} />
)}
</ThemeContext.Consumer>
);
}

Хотя старый способ все ещё работает, при написании нового кода используйте useContext():

function Button() {
// ✅ Рекомендуемый способ
const theme = useContext(ThemeContext);
return <button className={theme} />;
}

Пропсы

  • children: Функция. React вызовет ее, передав текущее значение контекста, и отрендерит возвращаемый результат. Значение контекста определяется тем же алгоритмом, что и в useContext(). Когда значение изменится — React повторно вызовет функцию и обновит UI.

Использование

Создание контекста

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

Вызовите createContext вне кода компонентов для создания одного или нескольких контекстов.

import { createContext } from 'react';

const ThemeContext = createContext('light');
const AuthContext = createContext(null);

createContext возвращает объект контекста. Компоненты могут получить значение контекста, передав его в useContext():

function Button() {
const theme = useContext(ThemeContext);
// ...
}

function Profile() {
const currentUser = useContext(AuthContext);
// ...
}

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

Контекст полезен возможностью передавать динамически изменяемые значения из ваших компонентов:

function App() {
const [theme, setTheme] = useState('dark');
const [currentUser, setCurrentUser] = useState({ name: 'Taylor' });

// ...

return (
<ThemeContext.Provider value={theme}>
<AuthContext.Provider value={currentUser}>
<Page />
</AuthContext.Provider>
</ThemeContext.Provider>
);
}

Теперь компонент Page и все компоненты внутри него, на каком бы уровне вложенности они не находились, будут “видеть” переданное значение контекста. Если данные изменятся, React выполнит повторный рендер читающих контекст компонентов.

Больше про чтение и передачу контекста с примерами.


Импорт и экспорт контекста из файла

Часто компонентам из разных файлов нужен доступ к одному и тому же контексту. Вот почему принято объявлять контекст в отдельном файле. Что бы сделать контекст доступным для других файлов вы можете использовать оператор export:

// Contexts.js
import { createContext } from 'react';

export const ThemeContext = createContext('light');
export const AuthContext = createContext(null);

Компоненты, объявленные в других файлах, могут использовать оператор import для чтения или предоставления данного контекста:

// Button.js
import { ThemeContext } from './Contexts.js';

function Button() {
const theme = useContext(ThemeContext);
// ...
}
// App.js
import { ThemeContext, AuthContext } from './Contexts.js';

function App() {
// ...
return (
<ThemeContext.Provider value={theme}>
<AuthContext.Provider value={currentUser}>
<Page />
</AuthContext.Provider>
</ThemeContext.Provider>
);
}

Это работает аналогично импорту и экспорту компонентов.


Возможные проблемы

Я не могу найти способ изменить значение контекста

Код наподобие этого определяет значение контекста по умолчанию:

const ThemeContext = createContext('light');

Это значение никогда не изменится. React использует его в качестве запасного варианта, если не может найти соответствующий провайдер выше.

Что бы контекст изменялся со временем, добавьте компоненты состояния и обёртки в провайдер контекста.