Real fetch
Real fetch in the Data fetching guide.
The fetcher is ordinary async code. Return the parsed value, throw on a bad status, and pass the signal:
src/http.tsxtsx
import { useResource, useStore } from "@shadow-js/core";
export interface Post {
readonly id: number;
readonly title: string;
}
async function getJson<T>(url: string, signal: AbortSignal): Promise<T> {
const response = await fetch(url, { signal });
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
return (await response.json()) as T;
}
export function PostView() {
const [id, setId] = useStore(1);
const post = useResource(id, (value, { signal }) =>
getJson<Post>(`/api/posts/${value}`, signal),
);
return (
<article>
<button type="button" onClick={() => setId((current) => current + 1)}>
next
</button>
<h1>{post.latest?.title}</h1>
<p>{post.loading ? "loading" : post.error === undefined ? "" : String(post.error)}</p>
</article>
);
}
response.json() is typed unknown-like data from the network: validate it (a schema library, or
hand-written checks) before trusting the as T cast, especially for data you render with innerHTML or
use to build URLs. When the request is aborted, fetch rejects with an AbortError; the resource ignores
the result of an aborted request, so the error never reaches the UI.