1. createResource — 异步数据源
createResource 是 SolidJS 处理异步数据的核心原语。它将一个异步函数包装成响应式 Signal,提供加载状态、错误状态和数据本身。
import { createResource } from "solid-js";
interface User { id: number; name: string; email: string; }
// 异步获取函数
const fetchUser = async (id: string): Promise<User> => {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
};
function UserCard() {
const [userId, setUserId] = createSignal("1");
// createResource(source, fetcher)
// source:依赖的 Signal,变化时自动重新请求
// fetcher:接收 source 值,返回 Promise
const [user, { refetch, mutate }] = createResource(userId, fetchUser);
return (
<div>
{/* user() 的状态:undefined(初始)/ Promise 中 / 数据 / 错误 */}
<p>loading: {String(user.loading)}</p>
<p>error: {user.error?.message}</p>
<Show when={!user.loading && !user.error}>
<h2>{user()?.name}</h2>
<p>{user()?.email}</p>
</Show>
{/* 切换用户 ID,自动重新请求 */}
<button onClick={() => setUserId("2")}>查看用户2</button>
{/* 手动重新请求 */}
<button onClick={refetch}>刷新</button>
</div>
);
}
createResource 的状态属性
-
resource()读取数据值(undefined 直到首次成功,之后是上次成功的数据)
-
resource.loading布尔值,请求进行中为 true
-
resource.error请求失败时的错误对象,成功时为 undefined
-
resource.state"unresolved" | "pending" | "ready" | "refreshing" | "errored"
-
refetch()手动触发重新请求
-
mutate(data)乐观更新:直接设置数据值,不触发请求
2. <Suspense> — 声明式加载状态
<Suspense> 配合 createResource 使用,当任意子组件有未完成的资源请求时,自动显示 fallback UI:
import { Suspense } from "solid-js";
function UserProfile() {
const params = useParams();
const [user] = createResource(() => params.id, fetchUser);
const [posts] = createResource(() => params.id, fetchUserPosts);
// 直接使用数据,不需要检查 loading 状态
return (
<div>
<h1>{user().name}</h1>
<For each={posts()}>
{(post) => <p>{post.title}</p>}
</For>
</div>
);
}
function App() {
return (
<Suspense fallback={
<div class="skeleton">
<div class="skeleton-avatar"></div>
<div class="skeleton-text"></div>
</div>
}>
<UserProfile />
</Suspense>
);
}
3. ErrorBoundary + Suspense 组合
import { ErrorBoundary, Suspense } from "solid-js";
function DataPage() {
return (
<ErrorBoundary
fallback={(err, reset) => (
<div class="error-state">
<p>加载失败: {err.message}</p>
<button onClick={reset}>重试</button>
</div>
)}
>
<Suspense fallback={<p>加载中...</p>}>
<DataComponent />
</Suspense>
</ErrorBoundary>
);
}
4. 并发请求
function Dashboard() {
// 多个 Resource 并行请求——不会互相等待
const [stats] = createResource(fetchStats);
const [users] = createResource(fetchUsers);
const [orders] = createResource(fetchOrders);
// Suspense 等待所有请求完成后统一显示
return (
<Suspense fallback={<p>加载仪表盘...</p>}>
<StatsPanel data={stats()} />
<UserTable data={users()} />
<OrderList data={orders()} />
</Suspense>
);
}
5. 实战:带加载/错误状态的数据列表
import { createResource, createSignal } from "solid-js";
import { For, Show, Suspense, ErrorBoundary } from "solid-js";
interface Article { id: number; title: string; author: string; date: string; }
const fetchArticles = async (page: number): Promise<Article[]> => {
const res = await fetch(`/api/articles?page=${page}`);
return res.json();
};
function ArticleList() {
const [page, setPage] = createSignal(1);
const [articles, { refetch }] = createResource(page, fetchArticles);
return (
<div>
<div class="toolbar">
<button onClick={refetch}>刷新</button>
<span>第 {page()} 页</span>
</div>
{/* state === "refreshing" 时显示刷新指示器 */}
<Show when={articles.state === "refreshing"}>
<div class="refresh-banner">正在更新...</div>
</Show>
<ErrorBoundary fallback={(err, reset) => (
<div>
<p>加载失败: {err.message}</p>
<button onClick={reset}>重试</button>
</div>
)}>
<Suspense fallback={<p>加载文章...</p>}>
<For each={articles()} fallback={<p>暂无文章</p>}>
{(article) => (
<article>
<h2>{article.title}</h2>
<p>{article.author} · {article.date}</p>
</article>
)}
</For>
</Suspense>
</ErrorBoundary>
<div class="pagination">
<button disabled={page() <= 1} onClick={() => setPage(p => p - 1)}>上一页</button>
<button onClick={() => setPage(p => p + 1)}>下一页</button>
</div>
</div>
);
}
本章小结:createResource 将异步请求封装为响应式 Signal,自动追踪 source 变化并重新请求,提供 loading/error/state 等状态属性。Suspense 配合 Resource 声明式处理加载状态,ErrorBoundary 捕获请求失败,refetch/mutate 支持手动控制。