The resource cache and server rendering
Server rendering and hydration provide a resource cache to useResource through ResourceCacheContext.
Server rendering and hydration provide a resource cache to useResource through ResourceCacheContext. A resource asks the cache for a key: the explicit key option, or a position-derived key. If the cache holds a value for that key, the first load uses it and the fetcher is not called. Later loads (refetch(), a source change) always fetch.
renderToStringrenders a pendingSuspenseas its fallback.renderToStringAsyncruns render passes until the resources the pass asked for have settled, and returns{ html, data }, wheredatamaps keys to values.hydrate(code, container, { data })serves those values to the matching resources, once each, so the browser does not fetch them again.- A rejected fetch is not cached.
src/server-data.tsxtsx
import { useResource } from "@shadow-js/core";
import { Suspense } from "@shadow-js/web";
import { renderToString, renderToStringAsync } from "@shadow-js/web/server";
function Name() {
const name = useResource(async () => "Ada", { key: "name" });
return <b>{name()}</b>;
}
function App() {
return (
<main>
<Suspense fallback={<i>loading</i>}>
<Name />
</Suspense>
</main>
);
}
console.log(renderToString(() => <App />)); // the fallback: nothing has resolved yet
const result = await renderToStringAsync(() => <App />);
console.log(result.html);
console.log(JSON.stringify(result.data));
<main data-hk="0-0-0"><!--[--><i data-hk="0-0-1-0f-0">loading</i><!--]--></main>
<main data-hk="0-0-0"><!--[--><b data-hk="0-0-1-0-0-0"><!--[-->Ada<!--]--></b><!--]--></main>
{"k:name":"Ada"}On the client, the same markup hydrates without calling the fetcher:
Streaming (renderToStream) and out-of-order boundaries, deferStream, hydration keys and what must match between server and client are in SSR, hydration and streaming.