Haunted — это библиотека для создания веб-компонентов на основе функционального подхода, позволяющая использовать React-подобные хуки в нативных кастомных элементах. Одним из ключевых инструментов для организации состояния и обмена данными между компонентами является контекст. Контекст позволяет передавать значения глубоко в дерево компонентов без необходимости пробрасывать их через пропсы на каждом уровне.
Контекст в Haunted создаётся с помощью функции
createContext. Она возвращает объект, содержащий два
основных свойства: Provider и Consumer.
import { createContext } from 'haunted';
const ThemeContext = createContext({
theme: 'light',
toggleTheme: () => {}
});
Важно: объект, переданный в
createContext, используется как значение по умолчанию. Если
компонент-потребитель находится вне Provider, он будет
получать именно это значение.
ProviderProvider применяется для оборачивания части дерева
компонентов, которым необходимо предоставить доступ к контексту.
Provider принимает проп value, который
определяет текущее значение контекста для всех вложенных
компонентов.
import { component, useState } from 'haunted';
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light');
return html`
<${ThemeContext.Provider} .value=${{ theme, toggleTheme }}>
${children}
<//>
`;
}
customElements.define('theme-provider', component(ThemeProvider));
Ключевой момент: обновление значения value
автоматически триггерит повторный рендер всех потребителей этого
контекста, что обеспечивает реактивность данных.
useContextДля доступа к значению контекста используется хук
useContext. Он принимает объект контекста и возвращает
текущее значение, предоставленное ближайшим Provider.
import { useContext } from 'haunted';
function ThemeButton() {
const { theme, toggleTheme } = useContext(ThemeContext);
return html`
<button @click=${toggleTheme}>
Текущая тема: ${theme}
</button>
`;
}
customElements.define('theme-button', component(ThemeButton));
Особенности работы useContext:
value в Provider вызовет повторный
рендер потребителей.Provider,
возвращается значение по умолчанию, указанное при создании
контекста.useContext можно вызывать внутри любого компонента,
созданного через component, и внутри других хуков
Haunted.Haunted поддерживает глубокие деревья компонентов.
Контекст передаётся всем потомкам, включая несколько уровней
вложенности. Если есть несколько провайдеров одного и того же контекста
в разных частях дерева, каждый компонент будет использовать ближайший
сверху Provider.
function NestedComponent() {
const { theme } = useContext(ThemeContext);
return html`
<p>Тема внутри вложенного компонента: ${theme}</p>
`;
}
function App() {
return html`
<${ThemeContext.Provider} .value=${{ theme: 'dark' }}>
<nested-component></nested-component>
<//>
`;
}
В этом примере NestedComponent получает значение
theme из ближайшего провайдера, даже если дерево
компонентов гораздо глубже.
Для управления несколькими типами состояния можно использовать
несколько контекстов одновременно. Каждый контекст создаётся и
предоставляется отдельно, а потребители используют соответствующий
useContext.
const AuthContext = createContext({ user: null });
function Profile() {
const { theme } = useContext(ThemeContext);
const { user } = useContext(AuthContext);
return html`
<div>
<p>Пользователь: ${user?.name || 'Гость'}</p>
<p>Текущая тема: ${theme}</p>
</div>
`;
}
Такой подход обеспечивает чистую и модульную структуру, позволяя каждому контексту отвечать за свою область данных.
Использование контекста в Haunted накладывает следующие особенности:
value. Если объект не
изменяется по ссылке, рендер не вызывается.value, например с использованием useState или
useMemo, чтобы избежать ненужных обновлений.const value = useMemo(() => ({ theme, toggleTheme }), [theme]);
Provider, может быть обычным
кастомным элементом или Haunted-компонентом.slots или динамические
DOM-элементы работает корректно, так как Provider
использует Shadow DOM-aware механизм подписки.useState и пробрасывать данные через пропсы.Контекст в Haunted сочетает реактивность хуков с мощью веб-компонентов, обеспечивая чистую архитектуру и предсказуемое управление состоянием даже в сложных приложениях.