useContext для работы с контекстом

useContext — это хук, который обеспечивает доступ к контексту в функциональных компонентах. Контекст используется для передачи данных между компонентами без необходимости пробрасывать их через пропсы на каждом уровне иерархии.

Создание контекста происходит с помощью функции createContext. Она возвращает объект с двумя ключевыми свойствами: Provider и Consumer. В современных проектах Consumer используется редко, поскольку useContext позволяет работать с контекстом напрямую.

import { createContext } from 'preact';
import { useContext } from 'preact/hooks';

const ThemeContext = createContext('light');

В этом примере создается контекст для темы с значением по умолчанию 'light'.

Провайдер контекста

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

<ThemeContext.Provider value="dark">
    <App />
</ThemeContext.Provider>

Здесь все компоненты внутри <App /> смогут получить доступ к значению "dark" через useContext.

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

Хук useContext принимает объект контекста, созданный через createContext, и возвращает текущее значение контекста, которое было передано через Provider.

function Toolbar() {
    const theme = useContext(ThemeContext);
    return <div style={{ background: theme === 'dark' ? '#333' : '#fff' }}>Toolbar</div>;
}

Если Toolbar находится вне <ThemeContext.Provider>, useContext вернет значение по умолчанию 'light'.

Обновление контекста

Значение контекста можно обновлять динамически, передавая новое значение в Provider. При этом все дочерние компоненты, использующие useContext, автоматически перерисуются с новым значением.

function App() {
    const [theme, setTheme] = useState('light');

    return (
        <ThemeContext.Provider value={theme}>
            <Toolbar />
            <button onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
                Переключить тему
            </button>
        </ThemeContext.Provider>
    );
}

Вложенные контексты

В Preact допустимо использовать несколько контекстов одновременно. Вложенные контексты не конфликтуют между собой, каждый компонент получает значение именно того контекста, который был передан через соответствующий Provider.

const AuthContext = createContext(null);

function UserProfile() {
    const theme = useContext(ThemeContext);
    const user = useContext(AuthContext);

    return (
        <div style={{ background: theme === 'dark' ? '#333' : '#fff' }}>
            {user ? `Привет, ${user.name}` : 'Гость'}
        </div>
    );
}

Отличия от React

В Preact useContext работает аналогично React, однако Preact более легковесен, поэтому важно помнить о производительности при частых обновлениях контекста. Каждый вызов setState в Provider инициирует перерисовку всех компонентов, использующих этот контекст. В крупных приложениях рекомендуется разделять контексты для независимых данных, чтобы избежать лишних ререндеров.

Советы по использованию

  • Разделять контексты по смыслу данных (тема, авторизация, настройки) для уменьшения перерисовок.
  • Использовать значения по умолчанию при создании контекста для безопасного доступа вне Provider.
  • Для больших приложений комбинировать useContext с useReducer для управления сложными состояниями внутри контекста.

Пример комплексного использования

const ThemeContext = createContext('light');
const AuthContext = createContext({ user: null });

function App() {
    const [theme, setTheme] = useState('light');
    const [user, setUser] = useState({ name: 'Алексей' });

    return (
        <ThemeContext.Provider value={theme}>
            <AuthContext.Provider value={user}>
                <Toolbar />
                <button onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
                    Переключить тему
                </button>
            </AuthContext.Provider>
        </ThemeContext.Provider>
    );
}

function Toolbar() {
    const theme = useContext(ThemeContext);
    const user = useContext(AuthContext);

    return (
        <div style={{ padding: '10px', background: theme === 'dark' ? '#333' : '#eee' }}>
            {user ? `Пользователь: ${user.name}` : 'Гость'}
        </div>
    );
}

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