Паттерны передачи данных между компонентами

Свойства (Props)

Props — основной способ передачи данных от родительского компонента к дочернему. В Preact props неизменяемы внутри дочернего компонента, что обеспечивает предсказуемость и стабильность состояния. Простейший пример:

import { h } from 'preact';

function Child({ message }) {
    return <p>{message}</p>;
}

function Parent() {
    return <Child message="Привет из родителя!" />;
}
  • Ключевые моменты:

    • Props всегда односторонние — данные передаются сверху вниз.
    • Для динамического обновления props используется состояние родителя или контекст.
    • Передача функций через props позволяет дочернему компоненту влиять на поведение родителя.
function Child({ onClick }) {
    return <button onCl ick={onClick}>Нажми меня</button>;
}

function Parent() {
    const handleClick = () => alert('Кнопка нажата');
    return <Child onCl ick={handleClick} />;
}

Состояние (State)

Компоненты Preact могут содержать локальное состояние через хук useState. Это состояние управляет внутренними данными и не зависит напрямую от props. Важный паттерн — поднятие состояния вверх (lifting state up).

import { h } from 'preact';
import { useState } from 'preact/hooks';

function Counter({ value, onChange }) {
    return (
        <div>
            <button onCl ick={() => onChange(value - 1)}>-</button>
            <span>{value}</span>
            <button onCl ick={() => onChange(value + 1)}>+</button>
        </div>
    );
}

function App() {
    const [count, setCount] = useState(0);
    return <Counter value={count} onCha nge={setCount} />;
}
  • Поднятие состояния позволяет нескольким компонентам синхронизировать данные, сохраняя их в родителе.
  • Локальное состояние удобно для временных или изолированных данных, которые не нужны другим компонентам.

Контекст (Context API)

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

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

const ThemeContext = createContext('light');

function Toolbar() {
    const theme = useContext(ThemeContext);
    return <div className={`toolbar ${theme}`}>Toolbar с темой {theme}</div>;
}

function App() {
    return (
        <ThemeContext.Provider value="dark">
            <Toolbar />
        </ThemeContext.Provider>
    );
}
  • Контекст не заменяет props, но облегчает управление глобальными данными.
  • Использование Provider позволяет динамически менять контекст на уровне поддеревьев компонентов.
  • Подписка на контекст через useContext автоматически обновляет компонент при изменении значения.

Callback-функции для взаимодействия дочерних и родительских компонентов

Прямое изменение состояния родителя из дочернего компонента невозможно без передачи функций. Паттерн обратного вызова (callback) решает эту задачу.

function Child({ notify }) {
    return <button onCl ick={() => notify('Данные из Child')}>Отправить</button>;
}

function Parent() {
    const handleNotification = message => console.log(message);
    return <Child notify={handleNotification} />;
}
  • Дочерний компонент остаётся чистым и не зависит от внутренней логики родителя.
  • Такой паттерн упрощает тестирование и повторное использование компонентов.

Хуки пользовательского состояния (Custom Hooks)

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

import { useState } from 'preact/hooks';

function useCounter(initial = 0) {
    const [count, setCount] = useState(initial);
    const increment = () => setCount(c => c + 1);
    const decrement = () => setCount(c => c - 1);
    return { count, increment, decrement };
}

function Counter() {
    const { count, increment, decrement } = useCounter(10);
    return (
        <div>
            <button onCl ick={decrement}>-</button>
            <span>{count}</span>
            <button onCl ick={increment}>+</button>
        </div>
    );
}
  • Пользовательские хуки позволяют повторно использовать логику между разными компонентами.
  • Сочетание хуков и props обеспечивает гибкий контроль данных.

Комбинирование паттернов

В больших приложениях чаще всего используется сочетание props, state и контекста:

  • Props — для передачи данных вниз по дереву.
  • State — для локального управления изменяемыми данными.
  • Контекст — для глобальных или сквозных данных.
  • Callback-функции — для обратной связи от дочерних компонентов.
  • Пользовательские хуки — для повторно используемой логики.
import { h, createContext } from 'preact';
import { useState, useContext } from 'preact/hooks';

const UserContext = createContext(null);

function Profile() {
    const user = useContext(UserContext);
    return <div>Пользователь: {user.name}</div>;
}

function App() {
    const [user, setUser] = useState({ name: 'Алексей' });
    return (
        <UserContext.Provider value={user}>
            <Profile />
            <button onCl ick={() => setUser({ name: 'Мария' })}>Сменить пользователя</button>
        </UserContext.Provider>
    );
}
  • Изменение состояния родителя автоматически обновляет дочерние компоненты через контекст.
  • Props и контекст можно комбинировать для локальных и глобальных данных одновременно.

Эффективное управление передачей данных между компонентами Preact основывается на чёткости потока данных, минимизации ненужных обновлений и использовании подходящих инструментов для каждой задачи: props для простого потока, state для локального состояния, context для глобального доступа, callback и хуки для гибкой логики.