SolidJS

SolidJS построен на принципе тонкой реактивности (fine-grained reactivity), при котором обновления происходят не на уровне виртуального DOM, а на уровне отдельных реактивных выражений. Такой подход позволяет минимизировать лишние пересчёты и обеспечивает предсказуемую производительность даже при сложных интерфейсах.

Основой реактивной модели являются сигналы (signals) — минимальные реактивные единицы состояния. Изменение сигнала приводит к точечному обновлению только тех вычислений, которые напрямую от него зависят.

import { createSignal } from "solid-js";

const [count, setCount] = createSignal(0);

setCount(count() + 1);

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

Сигналы и реактивные вычисления

Реактивные вычисления в SolidJS реализуются через эффекты (createEffect). Эффект автоматически отслеживает зависимости и повторно выполняется при изменении связанных сигналов.

import { createSignal, createEffect } from "solid-js";

const [name, setName] = createSignal("Solid");

createEffect(() => {
  console.log("Имя изменилось:", name());
});

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

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

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

Компоненты SolidJS представляют собой обычные функции, возвращающие JSX. При этом JSX компилируется в высоко оптимизированные вызовы DOM без промежуточного представления.

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

  return (
    <button onCl ick={() => setCount(count() + 1)}>
      {count()}
    </button>
  );
}

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

Отличие от виртуального DOM

В отличие от React-подобных библиотек, SolidJS не использует виртуальный DOM как промежуточный слой. Вместо этого применяется компиляция реактивных выражений в прямые DOM-операции.

Это приводит к следующим характеристикам:

  • отсутствие повторного рендеринга компонентов как функции
  • отсутствие reconciliation-алгоритма
  • обновление только конкретных узлов DOM
  • минимальная нагрузка на GC из-за отсутствия виртуальных деревьев

Управление побочными эффектами

Помимо createEffect, используется набор специализированных реактивных примитивов:

  • createMemo — мемоизированные вычисления
  • createResource — асинхронные источники данных
  • onMount / onCleanup — управление жизненным циклом

createMemo

import { createSignal, createMemo } from "solid-js";

const [count, setCount] = createSignal(1);

const doubled = createMemo(() => count() * 2);

Мемоизация позволяет избегать повторных вычислений, если зависимости не изменились.

createResource

import { createResource } from "solid-js";

const fetchUser = async (id) =>
  (await fetch(`/api/user/${id}`)).json();

const [user] = createResource(() => 1, fetchUser);

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

Управление жизненным циклом

Жизненный цикл компонентов в SolidJS минималистичен и основан на реактивных хуках.

import { onMount, onCleanup } from "solid-js";

function Example() {
  onMount(() => {
    console.log("Компонент смонтирован");
  });

  onCleanup(() => {
    console.log("Очистка перед удалением");
  });

  return <div />;
}

Отсутствие классов и сложной системы хуков делает модель жизненного цикла предсказуемой и локализованной внутри компонента.

Условный рендеринг и списки

SolidJS использует специализированные компоненты управления потоком:

  • Show
  • For
  • Switch / Match

Show

import { Show } from "solid-js";

<Show when={count() > 0} fallback={<div>Пусто</div>}>
  <div>Есть данные</div>
</Show>

For

import { For } from "solid-js";

<For each={items()}>
  {(item) => <div>{item}</div>}
</For>

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

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

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

import { createStore } from "solid-js/store";

const [state, setState] = createStore({
  user: { name: "Alex", age: 25 }
});

setState("user", "age", 26);

Stores поддерживают иммутабельные обновления с возможностью точечного изменения вложенных свойств без пересоздания всего объекта.

Компиляция и оптимизация

SolidJS активно использует компиляцию JSX. На этапе сборки:

  • JSX преобразуется в вызовы DOM API
  • реактивные выражения превращаются в подписки
  • статические части шаблона кешируются
  • динамические узлы связываются с сигналами

Такой подход переносит часть логики из runtime в build-time, снижая нагрузку на браузер.

Асинхронные данные и поток состояния

Асинхронность интегрируется через ресурсы, которые автоматически связываются с реактивными зависимостями.

Изменение сигнала может автоматически перезапускать загрузку данных, формируя реактивный поток:

  • сигнал изменился
  • ресурс перезапустился
  • состояние обновилось
  • UI точечно обновился

Масштабирование архитектуры

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

Основные принципы масштабирования:

  • разбиение логики на сигналы и мемо
  • локализация эффектов внутри компонентов
  • использование stores для структурированных данных
  • минимизация побочных эффектов вне реактивного контекста

Интероперабельность и экосистема

SolidJS может взаимодействовать с внешними библиотеками через прямой доступ к DOM-узлам и эффектам. Это позволяет интегрировать его в существующие приложения без полной миграции.

Реактивная система остаётся изолированной от внешнего кода, что предотвращает конфликт моделей состояния.