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 中,请将其替换为返回 promise 的 memo:const data = createMemo(() => fetch(url).then(r => r.json()))。 - 包裹顶层组件 – 如果组件在 promise 解析之前就进行渲染,请使用
<Loading fallback={<Spinner/>}>…</Loading>将其包裹。fallback 仅在首次挂载时显示。 - 替换每次重新获取时的加载动画 – 在你之前切换 loading 标志的地方,现在请读取
isPending(data)。使用该布尔值来渲染一个细微的指示器,同时保持现有 UI 在屏幕上。 - 转换乐观更新 – 如果你之前使用了
setState(prev => ({...prev, optimisticValue}))紧接着一个异步调用,请将其重写为const update = action(function* (newValue) { state = newValue; const server = yield fetch(...); state = reconcile(server); });。生成器(generator)会交出控制权直到服务器响应,然后自动更新响应式图谱(reactive graph)。 - 处理多个异步部分 – 根据需要嵌套
<Loading>边界,然后添加<Reveal>包裹器来决定它们是同时出现还是依次出现。这取代了 React 开发者通过复杂的逻辑检查来交错使用多个<Suspense>组件的模式。 - 测试流程 – 由于 Solid 在 promise 解析时不会重新渲染,请验证 UI 更新是否仍发生在预期的位置。响应式图谱会自动传播更改;无需额外的
useEffect调用。
尚在变动中
Solid 2.0 的 async API 目前处于 beta 阶段。在稳定版本发布之前,像 <Loading> 和 action 这样的名称可能会发生变化,文档也仍在不断演进。其核心理念——将 promise 视为响应式值——保持不变,但早期采用者应预见到随着库趋于稳定可能会出现细微的破坏性变更(breaking changes)。
谁将从中受益
- 数据获取需求较重的 React 团队 – 减少对外部状态库的需求,以及内置的 stale-while-revalidate 模式可以缩小 bundle 体积并简化代码库。
- 关注性能的应用 – 通过避免每次获取数据时都进行完整的组件重新渲染,Solid 提供了更平滑的视觉更新,尤其是在低端设备上。
- 厌倦了“加载动画闪烁”的开发者 –
<Loading>边界的“仅限首次加载”行为消除了在已有内容的上方闪烁加载动画这一常见烦恼。
可能的缺点
- Beta 阶段 – 在 API 稳定之前,长期项目可能需要为后续的迁移工作预留预算。
下一步关注点
请密切关注官方变更日志,留意 <Loading> 或 action 是否有任何更名。
总结: SolidJS 2.0 让你能将 promise 视为一等公民级别的响应式值,在数据刷新时保持 UI 稳定,并消除了对一系列 React 风格 hook 的需求。对于准备超越“以重新渲染为中心”模型的团队来说,迁移路径是清晰的,性能提升是显而易见的,而唯一的实际风险就是 beta 阶段常见的各种不确定性。
