Guides

获取数据

编辑此页面

对于大多数现代 Web 应用程序来说,数据获取是一项常见任务。 Solid 有一个内置实用程序 createResource ,它是为了简化数据获取而创建的。


createResource 是什么?

createResource 是专门为管理异步数据获取而设计的定制 signal 。它包装了异步操作,提供了一种处理各种状态的方法,包括加载、成功和错误状态。

此函数是非阻塞的,这意味着 createResource 保证应用程序保持响应,即使在信息检索期间也是如此。因此,可以避免传统异步处理的常见缺陷,例如数据获取期间 UI 无响应。


使用 createResource

createResource 需要一个返回 Promise 作为其参数的函数。调用时,createResource 返回一个具有响应属性(如加载、错误、最新等)的 signal。这些属性可用于根据当前响应状态有条件地渲染 JSX。

创建的 fetcher 函数会调用以获取数据,然后将其作为参数传递给 createResource

createResource 返回的 signal 提供了可以帮助基于当前响应式状态进行条件渲染的属性:

  • state: 操作的当前状态 (unresolved, pending, ready, refreshing, 或 errored)。
  • loading: 通过一个 boolean 值表示当前操作正在进行中。
  • error: 如果操作因一些原因失败,此属性将包含有关此错误的信息。它可能是带有错误消息的字符串,也可能是带有更详细信息的对象。
  • latest: 操作返回的最新数据或结果。

当源 signal 发生变化时,会基于这次改变触发一个内部的 fetch 以检索新数据。

import { createSignal, createResource, Switch, Match, Show } from "solid-js";
const fetchUser = async (id) => {
const response = await fetch(`https://swapi.dev/api/people/${id}/`);
return response.json();
};
function App() {
const [userId, setUserId] = createSignal();
const [user] = createResource(userId, fetchUser);
return (
<div>
<input
type="number"
min="1"
placeholder="Enter Numeric Id"
onInput={(e) => setUserId(e.currentTarget.value)}
/>
<Show when={user.loading}>
<p>Loading...</p>
</Show>
<Switch>
<Match when={user.error}>
<span>Error: {user.error}</span>
</Match>
<Match when={user()}>
<div>{JSON.stringify(user())}</div>
</Match>
</Switch>
</div>
);
}

每当 signal 值 userId 发生变化时,就会触发内部 fech 方法 fetchUseruser resource 的属性允许根据获取过程的不同状态进行条件渲染。

Switch/Match 提供了一种管理这些条件的方法。当获取成功并检索到用户数据时,user() 条件变为激活状态,并且渲染其内容。但是,如果获取时出现错误, user.error 将变为 true ,从而导致显示其相应的 Match 块。

除了 error 属性之外,loading 属性还提供了一种在数据获取期间向用户展示加载状态的方法。


调用多个异步事件

虽然您可以独立使用 createResource,但 Solid 提供了另一种方法来同步多个异步事件的显示。

Suspense 是 Solid 中的一个组件,旨在充当边界。它允许您在等待所有异步事件 resolve 时显示 fallback 占位符,从而防止显示部分加载内容:

import {
createSignal,
createResource,
Switch,
Match,
Suspense,
} from "solid-js";
const fetchUser = async (id) => {
const response = await fetch(`https://swapi.dev/api/people/${id}/`);
return response.json();
};
function App() {
const [userId, setUserId] = createSignal();
const [user] = createResource(userId, fetchUser);
return (
<div>
<input
type="number"
min="1"
placeholder="Enter Numeric Id"
onInput={(e) => setUserId(e.currentTarget.value)}
/>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Match when={user.error}>
<span>Error: {user.error.message}</span>
</Match>
<Match when={user()}>
<div>{JSON.stringify(user())}</div>
</Match>
</Switch>
</Suspense>
</div>
);
}

Suspense 能够识别其后代中的异步读取并采取相应的操作。此功能有助于删除任何可能在部分加载状态期间显示的中间组件。此外,您可以根据需要在 Suspense 中嵌套任意数量的组件,但当检测到加载状态时,只有最接近的祖先才会切换到 fallback 状态。


动态数据处理

对于 createResource 的第二个输出,有两种强大的方法旨在增强和简化数据管理的复杂性:

mutate

在即时反馈或响应性很重要的情况下,mutate 方法提供“乐观更新”。即使后台进程(例如服务器确认)仍在进行中,这些更新也会提供即时反馈。

此功能在任务列表等应用程序中特别有价值。例如,当用户输入新任务并单击 Add 按钮时,列表将立即刷新,而不管与服务器正在进行的数据通信如何。

import { For, createResource } from "solid-js";
function TodoList() {
const [tasks, { mutate }] = createResource(fetchTasksFromServer);
return (
<>
<ul>
<For each={tasks()}>{(task) => <li>{task.name}</li>}</For>
</ul>
<button
onClick={() => {
mutate((todos) => [...todos, "do new task"]); // add todo for user
// make a call to send to database
}}
>
Add Task
</button>
</>
);
}

refetch

当需要实时反馈时,可以使用 refetch 方法重新加载当前查询,而不管发生任何变化。当数据不断变化时,例如实时金融应用程序,此方法特别有用。

import { createResource, onCleanup } from "solid-js";
function StockPriceTicker() {
const [prices, { refetch }] = createResource(fetchStockPrices);
const timer = setInterval(() => {
refetch();
}, 1000);
onCleanup(() => clearInterval(timer));
}
报告此页面问题