Dados assíncronos
O createResource transforma uma promise em signal. Combine com o Suspense para estados de carregamento e com o ErrorBoundary para falhas.
createResource
import { createResource } from '@velozjs/dom';
// Sem fonte: busca uma vez.
const [user] = createResource(() => fetch('/api/me').then((r) => r.json()));
// Com fonte: busca de novo sempre que ela muda.
const [post] = createResource(postId, (id) => fetch(`/api/posts/${id}`).then((r) => r.json()));O fetcher recebe o valor da fonte e { value, refetching }. Pode devolver uma promise ou um valor comum. Enquanto a fonte for false, null ou undefined, nada é buscado.
Lendo um recurso
post(); // o valor, undefined até a primeira carga
post.state; // 'unresolved' | 'pending' | 'ready' | 'refreshing' | 'errored'
post.loading; // true enquanto há uma requisição em andamento
post.error; // o último erro
post.latest; // o último valor bem-sucedido (nunca lança erro)Todos são reativos. Se a última carga falhou, chamar post() lança o erro, e o ErrorBoundary mais próximo mostra o fallback dele.
Quando a fonte muda antes de uma requisição terminar, a resposta atrasada é ignorada. Quando o dono é descartado, os resultados pendentes são descartados também.
mutate e refetch
const [todos, { mutate, refetch }] = createResource(fetchTodos);
async function add(title: string) {
mutate([...(todos() ?? []), { title, done: false }]); // otimista
await api.add(title);
refetch();
}Suspense
O Suspense mostra o fallback enquanto um recurso lido dentro dele carrega pela primeira vez.
function Profile() {
const [user] = createResource(fetchUser);
return <h2>{() => user()?.name}</h2>;
}
<Suspense fallback={<p>Carregando…</p>}>
{() => <Profile />}
</Suspense>- Ele espera todos os recursos lidos dentro dele.
- Recargas não trazem o fallback de volta: o conteúdo atual fica, e você pode mostrar
user.loadingcomo um indicador discreto. - O conteúdo é criado uma vez e continua vivo enquanto escondido, então o estado dele sobrevive.
- Passe os filhos como função para que os recursos sejam criados dentro do limite.
Erros
<ErrorBoundary fallback={(error, reset) => <button onClick={reset}>{error.message}: tentar de novo</button>}>
{() => (
<Suspense fallback={<Spinner />}>
{() => <Profile />}
</Suspense>
)}
</ErrorBoundary>Teste
A demonstração da página inicial usa exatamente isso: um recurso com fonte, Suspense, ErrorBoundary, refetch e uma falha simulada.
No servidor
O renderToString não espera: recursos pendentes renderizam o fallback do Suspense. O renderToStringAsync espera os dados, coloca-os no HTML e devolve um script que entrega os valores ao hydrate(), então o cliente começa com eles em vez de buscar de novo. Veja Renderização no servidor.
Os recursos são associados entre servidor e cliente pela ordem de criação. Se essa ordem puder variar, dê a eles um nome estável:
createResource(fetchUser, { name: 'current-user' });