frontend/src/hooks/nanostores.ts
2025-07-31 23:05:55 +01:00

67 lines
No EOL
1.9 KiB
TypeScript

import {
implicit$FirstArg,
noSerialize,
NoSerialize,
QRL,
Signal,
useSignal,
useTask$,
useVisibleTask$,
} from "@builder.io/qwik";
import { Atom, WritableAtom } from "nanostores";
function writeable<T>(store: Atom<T> | WritableAtom<T>): store is WritableAtom<T> {
return typeof (store as WritableAtom<T>).set === 'function';
}
export function useNanostoreQrl<T>(qrl: QRL<WritableAtom<T> | Atom<T>>, defaultValue?: T): Signal<T> {
const signal = useSignal<T | undefined>(defaultValue);
const storeSignal = useSignal<NoSerialize<WritableAtom<T> | Atom<T>> | undefined>(undefined);
useTask$(async ({ track }) => {
let store: WritableAtom<T> | Atom<T> | undefined = storeSignal.value;
if (!store) {
const modified = await qrl.resolve();
storeSignal.value = noSerialize(modified);
store = modified;
}
if (signal.value === undefined && store.value !== undefined) {
signal.value = store.value;
}
const v = track(signal);
if (writeable(store) && v !== undefined && store.value !== v) {
store.set(v);
}
});
// eslint-disable-next-line qwik/no-use-visible-task
useVisibleTask$(async ({ cleanup }) => {
let store: WritableAtom<T> | Atom<T> | undefined = storeSignal.value;
if (!store) {
const modified = await qrl.resolve();
storeSignal.value = noSerialize(modified);
store = modified;
}
if (store.value !== undefined && signal.value !== store.value) {
signal.value = store.value;
}
const unsub = store.subscribe((value) => {
if (signal.value !== value) {
signal.value = value;
}
});
cleanup(unsub);
});
return signal as Signal<T>;
}
export const useNanostore$ = implicit$FirstArg(useNanostoreQrl);