Контекст (Context) в Inferno предназначен для передачи данных через дерево компонентов без необходимости явной прокладки этих данных через каждый уровень промежуточных компонентов. Он особенно полезен для глобальных настроек, тем, языковых локализаций и других данных, которые должны быть доступны в глубоко вложенных компонентах.
Контекст создаётся с помощью функции createContext из
пакета inferno:
import { createContext } from 'inferno';
const ThemeContext = createContext('light'); // 'light' — значение по умолчанию
Здесь 'light' — это значение по умолчанию, которое
используется, если компонент-потребитель контекста не находится внутри
провайдера.
Провайдер (Provider) отвечает за предоставление значения
контекста всему дереву компонентов, находящемуся ниже него:
import { render } from 'inferno';
import { ThemeContext } from './ThemeContext';
const App = () => (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
В примере выше все компоненты внутри Toolbar смогут
получить доступ к значению "dark". Значение провайдера
может быть динамическим, что позволяет изменять состояние контекста и
реактивно обновлять компоненты.
import { useState } from 'inferno';
const App = () => {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
<button onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Переключить тему
</button>
</ThemeContext.Provider>
);
};
Компоненты-потребители (Consumer) получают текущее
значение контекста через функцию-рендер. Это позволяет использовать
значение напрямую внутри JSX:
import { ThemeContext } from './ThemeContext';
const Toolbar = () => (
<ThemeContext.Consumer>
{theme => <div className={`toolbar ${theme}`}>Панель инструментов</div>}
</ThemeContext.Consumer>
);
Потребитель автоматически реагирует на изменения значения контекста и
перерендеривается при его обновлении. Важно понимать, что только
компоненты, находящиеся внутри соответствующего Provider,
получают актуальное значение. Если компонент вне провайдера,
используется значение по умолчанию.
В функциональных компонентах удобнее использовать хук
useContext:
import { useContext } from 'inferno';
import { ThemeContext } from './ThemeContext';
const Toolbar = () => {
const theme = useContext(ThemeContext);
return <div className={`toolbar ${theme}`}>Панель инструментов</div>;
};
Хук делает код более компактным и читаемым, избавляя от необходимости
оборачивать JSX в <ThemeContext.Consumer>.
Помимо контекста, данные традиционно передаются через пропсы
(props). Это базовый механизм, который обеспечивает
односторонний поток данных сверху вниз. Комбинирование пропсов и
контекста позволяет гибко управлять состоянием:
const Button = ({ label, onClick }) => (
<button onCl ick={onClick}>{label}</button>
);
const Toolbar = () => (
<div>
<Button label="Сохранить" onCl ick={() => console.log('Сохранено')} />
</div>
);
Контекст особенно полезен, когда одно и то же состояние требуется многим компонентам на разных уровнях вложенности. Пропсы удобны для передачи данных между близкими компонентами.
При использовании контекста следует учитывать, что любое изменение значения провайдера приводит к перерендеру всех потребителей. Для оптимизации можно:
value:import { useMemo, useState } from 'inferno';
const App = () => {
const [theme, setTheme] = useState('light');
const contextValue = useMemo(() => ({ theme, toggle: () => setTheme(theme === 'light' ? 'dark' : 'light') }), [theme]);
return (
<ThemeContext.Provider value={contextValue}>
<Toolbar />
</ThemeContext.Provider>
);
};
useMemo предотвращает ненужные пересоздания объекта при
каждом рендере, что снижает количество перерендеров дочерних
компонентов.
Хотя современный подход предполагает использование функциональных компонентов с хуками, классовые компоненты также поддерживают контекст:
class Toolbar extends Component {
render() {
return <div className={`toolbar ${this.context}`}>Панель инструментов</div>;
}
}
Toolbar.contextType = ThemeContext;
Присвоение contextType позволяет использовать
this.context внутри классового компонента для доступа к
текущему значению контекста.
Контекст в Inferno обеспечивает мощный и гибкий механизм передачи данных через дерево компонентов, сокращая необходимость многократной прокладки пропсов и упрощая организацию глобальных состояний.