Использование React библиотек

Fresh — фреймворк для Deno, основанный на Preact и архитектуре island-components. Несмотря на использование Preact вместо React, большая часть экосистемы React-библиотек может применяться напрямую или с минимальной адаптацией. Это достигается благодаря высокой степени совместимости API и поддержке JSX, хуков и контекста.

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


Совместимость React и Preact

Fresh использует Preact в режиме compat, что позволяет импортировать библиотеки, ожидающие React API.

Основные моменты совместимости:

  • preact/compat реализует интерфейсы react и react-dom
  • Поддерживаются хуки: useState, useEffect, useContext, useReducer и др.
  • Большинство UI-библиотек работают без изменений
  • Некоторые библиотеки, завязанные на внутренние реализации React или специфичные lifecycle-методы, могут требовать доработки

В Fresh настройка алиасов уже выполнена на уровне runtime, поэтому ручная конфигурация, как в Webpack или Vite, не требуется.


Импорт библиотек через ES-модули

Fresh работает исключительно с ES-модулями и URL-импортами. React-библиотеки подключаются через CDN, поддерживающие ESM.

Пример источников:

  • esm.sh
  • skypack.dev
  • cdn.jsdelivr.net

Импорт выполняется напрямую в файлах компонентов:

import { useForm } from "https://esm.sh/react-hook-form";

Особенности такого подхода:

  • Отсутствие node_modules
  • Автоматическое кэширование зависимостей Deno
  • Явное указание версий в URL для стабильности

Использование UI-библиотек

Большинство популярных UI-библиотек для React применимы во Fresh.

Material UI

Material UI использует Emotion и требует корректной работы с SSR. Во Fresh допустимо использование, но с учётом ограничений:

  • Стили генерируются на клиенте
  • Необходимо оборачивать компоненты в island
  • Глобальные темы работают корректно внутри island-границы

Пример импорта:

import Button from "https://esm.sh/@mui/material/Button";

Ant Design

Ant Design ориентирован на браузерную среду и крупный bundle. Использование возможно, но противоречит философии Fresh:

  • Высокий вес
  • Глобальные стили
  • Полная гидратация

Подходит для изолированных административных интерфейсов.


Headless-библиотеки

Наиболее естественный вариант для Fresh — headless-подход.

React Aria / React Spectrum

  • Логика поведения без навязанных стилей
  • Минимальное влияние на SSR
  • Хорошо работает в island-компонентах

Radix UI

  • Компоненты без визуального оформления
  • Используют хуки и контекст
  • Совместимы с Preact через compat

Пример:

import * as Dialog from "https://esm.sh/@radix-ui/react-dialog";

Управление состоянием

Fresh не навязывает систему управления состоянием. Возможны несколько подходов.

Локальное состояние

Использование useState и useReducer внутри island-компонентов — основной и предпочтительный вариант.

Zustand

Zustand хорошо подходит благодаря минимализму и отсутствию жёсткой привязки к React internals.

import { create } from "https://esm.sh/zustand";

Особенности:

  • Хранилище существует только на клиенте
  • Не требует Provider
  • Простая интеграция в island

Redux

Использование возможно, но не рекомендуется:

  • Избыточность для island-архитектуры
  • Сложности с SSR и гидратацией
  • Большой объём кода

Формы и валидация

React Hook Form

Одна из наиболее совместимых библиотек:

  • Работает с Preact
  • Не требует DOM-специфичных API
  • Хорошо сочетается с island-подходом
import { useForm } from "https://esm.sh/react-hook-form";

Formik

Работает, но менее эффективен:

  • Частые перерисовки
  • Большая зависимость от контекста

Работа с анимациями

Framer Motion

Framer Motion использует сложные DOM-манипуляции и не всегда стабилен в Preact-окружении. Использование возможно, но ограничено:

  • Только внутри island
  • Возможны проблемы с layout-анимациями

Альтернативы

  • CSS-анимации
  • @preact/signals для реактивных переходов
  • Простые transition-хуки

Маршрутизация и сторонние роутеры

Fresh имеет встроенную файловую маршрутизацию. Использование React Router или аналогов нецелесообразно:

  • Конфликт с серверной маршрутизацией
  • Дублирование логики
  • Потеря преимуществ SSR

React-библиотеки, ожидающие наличие роутера, должны использоваться без их routing-части либо с адаптацией.


Контекст и Providers

Контекст работает в пределах island-дерева. Глобальные провайдеры, оборачивающие всё приложение, противоречат архитектуре Fresh.

Рекомендуемый подход:

  • Минимальные Provider-деревья
  • Один Provider на island
  • Отсутствие глобального состояния между island-компонентами

Ограничения и подводные камни

  • Библиотеки, использующие react-dom/client напрямую, могут не работать
  • Использование useLayoutEffect на сервере приводит к предупреждениям
  • Любая клиентская библиотека требует island-обёртки
  • SSR-несовместимые зависимости должны быть изолированы

Архитектурный стиль использования библиотек

Характерный паттерн для Fresh:

  • Сервер: чистые JSX-шаблоны без состояния
  • Клиент: небольшие island-компоненты с логикой
  • Библиотеки подключаются только там, где реально нужна интерактивность
  • Минимизация веса и области гидратации

Такой подход позволяет использовать богатую экосистему React, сохраняя ключевые преимущества Fresh: скорость, простоту и строгую серверную ориентацию.