SolidJS: по-настоящему реактивный JavaScript-фреймворк
1. «Святой Грааль» фронтенд-фреймворков: производительность и удобство
С тех пор как React популяризировал виртуальный DOM (Virtual DOM), VDOM словно стал обязательной частью современных фронтенд-фреймворков. Он хранит в памяти виртуальное представление UI и с помощью алгоритма diff вычисляет минимально необходимые обновления DOM, улучшая опыт разработки и производительность в большинстве сценариев.
Но VDOM не обходится бесплатно. Он занимает память, а процесс diff требует вычислительных ресурсов. Отсюда возникает вопрос: можно ли обойти VDOM и точно применять изменения состояния непосредственно к DOM, сохранив при этом декларативный, похожий на React опыт разработки?
SolidJS даёт свой ответ.
2. Основа SolidJS: мелкозернистая реактивность (Fine-Grained Reactivity)
SolidJS — декларативный реактивный JavaScript-фреймворк. Он использует JSX и внешне очень похож на React, однако его внутренние принципы совершенно иные.
Компилятор SolidJS преобразует JSX-код в оптимальные нативные операции с DOM. Вместо VDOM он создаёт граф зависимостей из реактивных «сигналов» (Signals). Когда значение сигнала меняется, повторно выполняются только подписанные на него «эффекты» (Effects) или вычисления (Memos).
Модель, меняющая привычное мышление: компонент выполняется только один раз!
В React при изменении state или props вся функция компонента выполняется повторно. В SolidJS функция компонента выполняется от начала до конца только один раз.
import { createSignal } from 'solid-js';
function Counter() {
console.log('Component function runs!'); // 这句话只会在组件挂载时打印一次
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
return (
<button type="button" onClick={increment}>
Count: {count()}
</button>
);
}При нажатии на кнопку обновляются только считыватель сигнала count() и зависящий от него текстовый DOM-узел. Сама функция Counter повторно не запускается. Такие «хирургически точные» обновления и обеспечивают исключительную производительность SolidJS.
3. Основные API
Реактивная система SolidJS в основном состоит из трёх базовых примитивов:
createSignal(initialValue): Создаёт реактивный сигнал и возвращает getter и setter:[count, setCount].createEffect(() => {}): Создаёт «эффект», который автоматически отслеживает все прочитанные внутри него сигналы и выполняется снова при изменении любого из них. Отлично подходит для побочных эффектов, например ручной работы с DOM.createMemo(() => {}): Создаёт кэшируемое производное вычисляемое значение. Оно пересчитывается только при изменении внутренних зависимостей-сигналов.
import { createSignal, createEffect } from 'solid-js';
function App() {
const [firstName, setFirstName] = createSignal('John');
const [lastName, setLastName] = createSignal('Smith');
// createEffect 会在 firstName 或 lastName 变化时自动运行
createEffect(() => {
console.log(`Full name: ${firstName()} ${lastName()}`);
});
// ...
}4. Почему стоит выбрать SolidJS?
- Исключительная производительность: SolidJS часто занимает верхние позиции в независимых тестах, а его производительность очень близка к нативному JavaScript-коду.
- Очень маленький размер пакета: Благодаря отсутствию VDOM runtime основной пакет имеет небольшой размер.
- Знакомый опыт разработки: Если вы знакомы с React Hooks, то сможете быстро освоить SolidJS. Сочетание JSX и реактивных примитивов одновременно мощное и понятное.
- Настоящая реактивность: Его модель ближе к MobX или Composition API во Vue, но компилятор позволяет реализовать её без затрат во время выполнения.
Заключение
SolidJS представляет важное направление развития фронтенд-фреймворков: компилятор выполняет больше работы во время сборки, чтобы сократить объём кода во время выполнения и повысить производительность. Он доказывает, что от ограничений виртуального DOM можно полностью отказаться, не жертвуя декларативным опытом разработки. Для приложений, стремящихся к максимальной производительности, SolidJS предлагает крайне привлекательный вариант.