SolidJS 2.0 ships with a native async-data model that lets a component treat a promise like any other reactive value, and it does so without the cascade of re-renders that React developers see with Suspense and hooks. The change matters because it keeps UI on screen while data refreshes, cuts boilerplate, and offers a concrete path for React teams to move their data-fetching code over to Solid.
Why Solid’s async model feels different
In React, a component that needs data usually calls a hook (often a custom one) that returns a promise-like object, then wraps the UI in <Suspense> to show a fallback while the promise resolves. Every time the promise settles, React schedules a re-render; if the same component later refetches, the fallback can flash over content that is already visible.
Solid flips the script. A promise is simply a value that the reactive graph watches. When a computation reads that value, the graph pauses that read until the promise resolves, but the rest of the UI stays rendered. The first time a component mounts, a <Loading> boundary can display a fallback; after that, a refetch leaves the existing DOM untouched until the new data arrives. No explicit “await” inside the component, no createResource, no manual state toggles.
The core primitives
<Loading>boundary – Replaces React’s<Suspense>. It shows a fallback only on the initial load. After the first paint, a pending read does not replace the UI; the old content remains until the fresh value resolves. Pass anonprop to force a spinner on a specific refetch.<Reveal>component – Controls how multiple<Loading>boundaries appear together. Choose:- Sequential: boundaries reveal one after another in DOM order.
- Together: all reveal at once when every piece of data is ready.
- Natural: each reveals as soon as its own data lands.
isPendingsignal – Returnstruewhile a particular read is in flight. Use it to overlay a thin loading bar or subtle animation while the main content stays visible, giving you “stale-while-revalidate” for free.actiongenerator – Replaces React’s mutable-state updates. Anaction(function*…)can optimistically update the UI,yieldto wait for a server response, then reconcile the result when the promise resolves. The UI feels instant, and the reconciliation step is baked into the primitive.
How the pieces map to React concepts
| Feature | React approach | Solid 2.0 approach |
|---|---|---|
| Data fetching | use() (experimental) or third-party hooks; result wrapped in <Suspense> |
createMemo (or similar) that returns a promise; read directly in JSX |
| Loading UI | <Suspense> may re-trigger fallback on every refetch |
<Loading> only on first load; refetch keeps old UI |
| Refreshing | useTransition to defer UI updates |
isPending signals pending reads without UI swap |
| Mutations | useState/useReducer + async calls, often wrapped in custom actions |
action(function*…) with built-in optimistic handling |
The practical upshot is that Solid builds what React treats as separate hooks into the core reactivity engine.
A step-by-step migration guide
- Определите источник данных – В React у вас, скорее всего, есть
const data = useMyFetch(url). В Solid замените это наmemo, которое возвращает промис:const data = createMemo(() => fetch(url).then(r => r.json())). - Оберните компонент верхнего уровня – Если компонент рендерится до того, как промис разрешится, оберните его в
<Loading fallback={<Spinner/>}>…</Loading>. Fallback отображается только при первом монтировании. - Замените спиннеры при каждом повторном запросе – Там, где вы раньше переключали флаг загрузки, теперь считывайте
isPending(data). Используйте это булево значение для отображения ненавязчивого индикатора, пока текущий интерфейс остается на экране. - Преобразуйте оптимистичные обновления – Если у вас было
setState(prev => ({...prev, optimisticValue})), за которым следовал асинхронный вызов, перепишите это какconst update = action(function* (newValue) { state = newValue; const server = yield fetch(...); state = reconcile(server); });. Генератор передает управление до ответа сервера, а затем автоматически обновляет реактивный граф. - Обработка нескольких асинхронных частей – Вкладывайте границы
<Loading>по мере необходимости, а затем добавьте обертку<Reveal>, чтобы решить, должны ли они появляться вместе или по очереди. Это заменяет паттерны, в которых разработчики React использовали несколько компонентов<Suspense>с разным временем появления через сложные проверки состояния. - Протестируйте процесс – Поскольку Solid не выполняет рендеринг при разрешении промиса, убедитесь, что обновления UI происходят там, где вы ожидаете. Реактивный граф распространяет изменения автоматически; нет необходимости в дополнительных вызовах
useEffect.
Что всё еще находится в стадии разработки
Async API в Solid 2.0 сейчас находится в бета-версии. Названия вроде <Loading> и action могут измениться до стабильного релиза, а документация всё еще дополняется. Основная идея — отношение к промисам как к реактивным значениям — остается неизменной, но ранним последователям стоит ожидать небольших ломающих изменений по мере стабилизации библиотеки.
Кому это принесет пользу
- Команды React с интенсивной загрузкой данных – Снижение потребности во внешних библиотеках управления состоянием и встроенный паттерн stale-while-revalidate могут уменьшить размер бандла и упростить кодовую базу.
- Приложения, ориентированные на производительность – Избегая полного рендеринга компонентов при каждом запросе, Solid обеспечивает более плавные визуальные обновления, особенно на слабых устройствах.
- Разработчики, уставшие от «вспышек спиннера» – Поведение границы
<Loading>«только при первой загрузке» устраняет распространенную проблему, когда спиннер мелькает поверх уже видимого контента.
Возможные недостатки
- Статус бета-версии – Пока API не стабилизируется, долгосрочным проектам, возможно, придется закладывать ресурсы на последующую миграцию.
За чем следить дальше
Следите за официальным журналом изменений (changelog) на предмет переименования <Loading> или action.
Итог: SolidJS 2.0 позволяет относиться к промисам как к полноценным реактивным значениям, сохраняя стабильность UI во время обновления данных и избавляя от необходимости использовать набор хуков в стиле React. Для команд, готовых выйти за рамки модели, ориентированной на рендеринг, путь миграции ясен, выигрыш в производительности ощутим, а единственный реальный риск — привычная неопределенность стадии бета-тестирования.
