32. Solid 2.0: что нового
Solid 2.0 — это не просто обновление, а переосмысление модели реактивности. Сохраняя обратную совместимость в синтаксисе, Solid 2.0 переписывает ядро: сигналы, эффекты, асинхронность и рендеринг работают по принципиально новым правилам.
Solid 2.0 ещё в разработке (alpha). Информация актуальна на момент написания статьи и может измениться.
Что меняется в сигналах
Заголовок раздела «Что меняется в сигналах»Solid 1.x: геттеры-функции
Заголовок раздела «Solid 1.x: геттеры-функции»В Solid 1.x сигнал — пара [getter, setter]. Значение читается вызовом функции:
// Solid 1.xconst [count, setCount] = createSignal(0);console.log(count()); // вызываем как функциюSolid 2.0: прямой доступ через .value
Заголовок раздела «Solid 2.0: прямой доступ через .value»В Solid 2.0 сигналы имеют свойство .value — читать и писать можно напрямую:
// Solid 2.0 — новый APIimport { signal } from 'solid-js';
const count = signal(0);console.log(count.value); // читаем через .valuecount.value = 5; // пишем через .value = ...
// Старый синтаксис () — по-прежнему работает для совместимостиconsole.log(count()); // ещё поддерживаетсяУниверсальная реактивность
Заголовок раздела «Универсальная реактивность»В Solid 1.x реактивность привязана к DOM-рендерингу. В Solid 2.0 — это автономная система, независимая от рендеринга:
// Solid 2.0: реактивность без компонентовimport { signal, effect, computed } from 'solid-js/universal';
// Работает в Node.js, Web Worker, CLI — без DOM!const firstName = signal('Иван');const lastName = signal('Петров');const fullName = computed(() => `${firstName.value} ${lastName.value}`);
effect(() => { console.log('Имя изменилось:', fullName.value);});
firstName.value = 'Алексей'; // → 'Имя изменилось: Алексей Петров'Async by default
Заголовок раздела «Async by default»Solid 2.0 делает асинхронность первоклассной концепцией. Каждый сигнал может быть асинхронным:
// Solid 2.0: async сигналыimport { signal, asyncSignal } from 'solid-js';
// Сигнал с асинхронной инициализациейconst user = asyncSignal(async () => { const res = await fetch('/api/user'); return res.json();});
// Чтение возвращает Promise или значениеfunction Profile() { return ( // Автоматически создаёт Suspense-граница <p>{user.value.name}</p> );}Новый рендеринг
Заголовок раздела «Новый рендеринг»Solid 2.0 вводит компилируемые компоненты — JSX трансформируется в более оптимальный код:
// Solid 1.x JSX → компилируется в:function Counter(props) { const [count, setCount] = createSignal(0); return createComponent(Button, { get children() { return count(); }, onClick: () => setCount(c => c + 1) });}
// Solid 2.0 JSX → компилируется в оптимизированный вид:function Counter(props) { const count = signal(0); // Компилятор создаёт точечные обновления без createComponent overhead return /* compiled template */;}Изменения в TypeScript
Заголовок раздела «Изменения в TypeScript»Solid 2.0 улучшает типизацию — signal() полностью выводит типы:
// Solid 1.x — нужны явные genericconst [items, setItems] = createSignal<string[]>([]);
// Solid 2.0 — тип выводится автоматическиconst items = signal<string[]>([]);items.value = ['один', 'два']; // TypeScript знает тип!
// Новые utility-типыimport type { Signal, ReadSignal, MaybeSignal } from 'solid-js';
// Signal<T> — сигнал с .value// ReadSignal<T> — только для чтения// MaybeSignal<T> — T | Signal<T> (для пропсов, которые могут быть сигналами)function MyComponent(props: { count: MaybeSignal<number> }) { // работает и с числом, и с сигналом!}SolidStart 2.0
Заголовок раздела «SolidStart 2.0»SolidStart 2.0 построен поверх Vinxi и приносит кардинальные изменения:
// SolidStart 2.0: новые Server Functionsimport { action, query } from '@solidjs/router';
// Server Query — кешируемый серверный запросconst getUser = query(async (id: string) => { 'use server'; return db.users.findOne(id);}, 'getUser');
// Server Action — мутация на сервереconst updateUser = action(async (data: FormData) => { 'use server'; await db.users.update(Object.fromEntries(data)); return redirect('/profile');});
// Использование в компонентеfunction ProfilePage() { const user = createAsync(() => getUser(params.id));
return ( <form action={updateUser} method="post"> <input name="name" value={user()?.name} /> </form> );}Сравнение: 1.x vs 2.0
Заголовок раздела «Сравнение: 1.x vs 2.0»| Концепция | Solid 1.x | Solid 2.0 |
|---|---|---|
| Чтение сигнала | count() | count.value (или count()) |
| Запись сигнала | setCount(5) | count.value = 5 |
| Эффекты | createEffect(() => {...}) | effect(() => {...}) |
| Мемо | createMemo(() => ...) | computed(() => ...) |
| Реактивность | Только в DOM | Универсальная |
| Async | createResource | asyncSignal, createAsync |
| Рендеринг | createComponent | Компилируемые шаблоны |
Миграция с 1.x на 2.0
Заголовок раздела «Миграция с 1.x на 2.0»Solid 2.0 сохраняет обратную совместимость через codemods:
# Автоматическая миграцияnpx solid-codemod@latest migrate-to-v2 ./src
# Проверка deprecated APInpx solid-codemod@latest check ./srcБольшинство компонентов продолжат работать без изменений — createSignal, createEffect никуда не денутся, просто появятся алиасы.
Интерактивный пример
Заголовок раздела «Интерактивный пример»Сравнение концепций Solid 1.x и 2.0 в одном демо: