Files
djledda-web/app/useAsyncState.ts
Daniel Ledda bcb820f35e nice
2024-10-31 23:46:23 +01:00

51 lines
1.6 KiB
TypeScript

import { onMounted, onServerPrefetch, useSSRContext, shallowRef, type ShallowRef } from 'vue';
declare global {
// deno-lint-ignore no-var
var appstate: Partial<Record<string, unknown>>;
}
export default function useAsyncState<T>(key: string, getter: (context: { hostUrl: string }) => Promise<T | null>, options?: { suspensible: boolean }): { result: ShallowRef<T | null>, stateIsReady: Promise<unknown> } {
const ssrContext = useSSRContext<{ registry: Record<string, unknown> }>();
const isClient = typeof ssrContext === 'undefined';
const registry = ssrContext?.registry ?? globalThis?.appstate;
const hostUrl = isClient ? globalThis.location.origin : 'http://localhost:8080';
const state = shallowRef<T | null>(null);
let resolve = () => {};
const promise = new Promise<void>((res) => {
resolve = res;
});
if (key in registry) {
state.value = registry[key] as T;
delete registry[key];
resolve();
} else {
if (!isClient) {
resolve();
}
onServerPrefetch(async () => {
const result = await getter({ hostUrl });
registry[key] = result;
state.value = result;
});
if (options?.suspensible ?? true) {
getter({ hostUrl }).then((result) => {
state.value = result;
resolve();
}).catch(resolve);
} else {
onMounted(async () => {
state.value = await getter({ hostUrl });
resolve();
});
}
}
return { result: state, stateIsReady: promise };
}