51 lines
1.6 KiB
TypeScript
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 };
|
|
}
|