Prerendering async data #950
-
Similar to the question asked in #305 I have a collection of posts/entries coming from an API, while developing I am happy for them to be requested real time but ideally I would like to build them statically for production using prerender. Is there a built in way to do this? I did take a look at |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
The docs site works by patching Lines 7 to 11 in 3c5672e This has become built-in as of #934 (as it's pretty handy) though, so you won't need to do that manually if that's the behavior you want. Fetching a local file (using a relative specifier, like However, for external data sources (as it sounds like you have), you can lightly modify import { useState } from 'preact/hooks';
const CACHE = new Map();
async function load(url) {
const res = await fetch(url);
const { html } = await res.json();
return { html };
}
export function useContent(url) {
let update = useState(0)[1];
let p = CACHE.get(url);
if (!p) {
p = load(url);
CACHE.set(url, p);
p.then(
v => update((p.v = v)),
e => update((p.e = e))
);
}
if (p.v) return p.v;
if (p.e) throw p.e;
throw p;
} Then in our component: function MyComponent() {
const { html } = useContent('https://example.com/some-resource');
}
Now, Hope this helps, let me know if you have any issues. |
Beta Was this translation helpful? Give feedback.
-
Okay this is incredible and absolutely works, could I be a pain and check my understanding as to why Is it because we The documentation definitely hints at this:
I just had no idea this could be extended to hooks as well. |
Beta Was this translation helpful? Give feedback.
-
For anyone who comes across this thread in the future here is a generic hook I've created to do this with any promise. import { useState } from "preact/hooks";
const CACHE = new Map();
export const usePromise = <T = any>(
key: string,
handler: (key?: string) => Promise<T>
) => {
const [_, update] = useState<unknown>(null);
let value = CACHE.get(key);
if (value === undefined) {
value = handler(key);
CACHE.set(key, value);
value.then((res: unknown) => update((value.res = res)));
}
if (value.res) {
return value.res as Awaited<ReturnType<typeof handler>>;
}
throw value;
}; It can then be used like: const response = usePromise('some-key', async () => {
const resp = await fetch('https://...');
return resp.json();
}); Or even create some additional hooks from that base hook: const useFetch = (url: string) => usePromise(url, async () => {
const resp = await fetch(url);
return resp.json();
}); Haven't run into any issues yet. |
Beta Was this translation helpful? Give feedback.
The docs site works by patching
fetch()
to afs.readFile()
implementation, which you can find here:wmr/docs/public/prerender.js
Lines 7 to 11 in 3c5672e
This has become built-in as of #934 (as it's pretty handy) though, so you won't need to do that manually if that's the behavior you want. Fetching a local file (using a relative specifier, like
fetch('/foo.js')
) will automatically usefs
when prerendering.However, for exter…