Концепции реактивного программирования

Preact — это легковесная альтернатива React, сохраняющая большую часть API и концепций. Основой работы с Preact является реактивное обновление интерфейса при изменении состояния компонентов. В отличие от традиционного императивного подхода, где программист управляет DOM напрямую, реактивный подход строится вокруг отдельных компонентов и их состояния.

Компоненты и JSX

Компоненты Preact могут быть функциональными или классовыми, хотя предпочтение отдаётся функциональному подходу с хуками. JSX используется для декларативного описания структуры интерфейса:

import { h } from 'preact';

function App() {
  return (
    <div>
      <h1>Привет, Preact!</h1>
    </div>
  );
}

JSX компилируется в вызовы h(), которые создают виртуальное представление элементов. Виртуальный DOM обеспечивает эффективное обновление реального DOM при изменениях состояния.

Состояние компонента

Состояние в функциональных компонентах управляется через хук useState:

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

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Счётчик: {count}</p>
      <button onCl ick={() => setCount(count + 1)}>Увеличить</button>
    </div>
  );
}

Каждый вызов setCount триггерит перерисовку компонента, но Preact выполняет её оптимально, обновляя только изменённые узлы DOM.

Эффекты и жизненный цикл

Хук useEffect позволяет управлять побочными эффектами и жизненным циклом компонента:

import { useEffect } from 'preact/hooks';

useEffect(() => {
  console.log('Компонент смонтирован или обновлён');

  return () => {
    console.log('Компонент размонтирован');
  };
}, [count]);
  • Первый аргумент — функция эффекта.
  • Возвращаемая функция — очищение ресурсов (аналог componentWillUnmount).
  • Второй аргумент — массив зависимостей. Эффект вызывается при изменении этих зависимостей.

Контекст и глобальное состояние

Preact поддерживает контекст для передачи данных через дерево компонентов без пропсов:

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

const ThemeContext = createContext('light');

function Toolbar() {
  const theme = useContext(ThemeContext);
  return <div>Текущая тема: {theme}</div>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

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

Оптимизация производительности

Preact минимизирует размер и накладные расходы на виртуальный DOM. Для повышения производительности важны следующие подходы:

  • Использование key при рендеринге списков для корректного диффинга.
  • Разделение компонентов на мелкие, независимые части, чтобы локализовать перерисовки.
  • Применение memo для предотвращения ненужных рендеров:
import { memo } from 'preact/compat';

const ExpensiveComponent = memo(function Expensive({ data }) {
  return <div>{data}</div>;
});

Реактивные свойства и события

Preact автоматически слежет за изменениями состояния и пропсов. Обновления выполняются в виде реактивных вычислений:

  • Props — входные данные компонента.
  • State — локальные данные компонента.
  • Events — реакция на пользовательские действия.

События, такие как onClick, onInput, связываются напрямую с функциями, вызывающими обновление состояния. Preact гарантирует, что после изменения состояния интерфейс останется синхронизированным.

Заключение концепций

Реактивное программирование в Preact строится на нескольких ключевых принципах:

  • Декларативность: структура интерфейса описывается через JSX, а не через прямые манипуляции DOM.
  • Состояние и эффекты: все изменения данных приводят к автоматическому обновлению компонентов.
  • Контекст и хуки: позволяют создавать гибкие и масштабируемые приложения.
  • Оптимизация через виртуальный DOM: обновляются только изменившиеся узлы, что повышает производительность.

Эти концепции делают Preact эффективным инструментом для создания лёгких и реактивных веб-приложений, сохраняя при этом совместимость с большинством подходов React.