В Preact контекст представляет собой способ передачи данных через дерево компонентов без необходимости вручную прокидывать их через каждое звено. Контексты особенно полезны для глобальных состояний, таких как тема оформления, настройки языка или данные авторизации.
Создание контекста выполняется с помощью функции
createContext:
import { createContext } from 'preact';
import { useContext } from 'preact/hooks';
const ThemeContext = createContext('light');
ThemeContext здесь создаёт объект контекста с дефолтным
значением 'light'. Любой компонент в дереве может получить
это значение через useContext(ThemeContext).
Для передачи значений используется компонент-провайдер
Provider, который создаёт область видимости контекста:
<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>
Когда приложение использует несколько контекстов одновременно, провайдеры можно вкладывать друг в друга:
import { createContext } from 'preact';
import { useContext } from 'preact/hooks';
const ThemeContext = createContext('light');
const AuthContext = createContext({ user: null });
function App() {
const theme = useContext(ThemeContext);
const auth = useContext(AuthContext);
return (
<div className={theme}>
{auth.user ? `Привет, ${auth.user.name}` : 'Гость'}
</div>
);
}
function Root() {
return (
<ThemeContext.Provider value="dark">
<AuthContext.Provider value={{ user: { name: 'Иван' } }}>
<App />
</AuthContext.Provider>
</ThemeContext.Provider>
);
}
Ключевой момент: порядок вложенности провайдеров имеет значение только для вложенных компонентов, но каждый контекст остаётся независимым. Компонент может использовать несколько контекстов одновременно, не создавая конфликтов.
Значения контекста можно изменять динамически. Это особенно полезно для темы оформления, состояния авторизации или языковых настроек:
import { useState } from 'preact/hooks';
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemeSwitcher() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Сменить тему
</button>
);
}
В этом примере изменение темы автоматически обновляет все компоненты,
использующие ThemeContext, благодаря реактивной природе
Preact.
Для удобства работы с несколькими контекстами часто создаются кастомные хуки, которые агрегируют данные из нескольких источников:
function useAppContext() {
const theme = useContext(ThemeContext);
const auth = useContext(AuthContext);
return { theme, auth };
}
function Dashboard() {
const { theme, auth } = useAppContext();
return (
<div className={theme}>
{auth.user ? `Добро пожаловать, ${auth.user.name}` : 'Пожалуйста, войдите'}
</div>
);
}
Такой подход упрощает использование множественных контекстов и
улучшает читаемость кода, уменьшая количество useContext
вызовов внутри компонентов.
Использование множества контекстов может повлиять на рендеринг компонентов. Каждый раз, когда значение контекста изменяется, все компоненты-потребители внутри области видимости провайдера перерисовываются. Чтобы минимизировать лишние рендеры:
useMemo:import { useMemo } from 'preact/hooks';
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, setUser }), [user]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
Множественные контексты в Preact позволяют гибко управлять состоянием и обеспечивают масштабируемую архитектуру приложения, сохраняя чистоту кода и минимизируя передачу пропсов вручную.