From 89695a9accb228e03d5ac59adfbceed4e9f5e8b1 Mon Sep 17 00:00:00 2001 From: Gigiaj Date: Fri, 20 Jun 2025 16:19:50 -0500 Subject: [PATCH] Add a method to async interact with the local storage --- src/app/state/utils/atomWithIndexedDB.ts | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/app/state/utils/atomWithIndexedDB.ts diff --git a/src/app/state/utils/atomWithIndexedDB.ts b/src/app/state/utils/atomWithIndexedDB.ts new file mode 100644 index 00000000..fea8bb95 --- /dev/null +++ b/src/app/state/utils/atomWithIndexedDB.ts @@ -0,0 +1,48 @@ +import { atom, PrimitiveAtom } from 'jotai'; +import type { SetStateAction } from 'jotai'; +import { get as getFromDB, set as setInDB } from 'idb-keyval'; + +export const setIndexedDBItem = async (key: string, value: T) => { + await setInDB(key, value); +}; + +export const atomWithIndexedDB = (key: string, initialValue: T): PrimitiveAtom => { + const channel = new BroadcastChannel(key); + + const baseAtom = atom(initialValue); + let isInitialized = false; + + baseAtom.onMount = (setAtom) => { + (async () => { + const storedValue = await getFromDB(key); + if (storedValue !== undefined && !isInitialized) { + setAtom(storedValue); + } + isInitialized = true; + })(); + + const handleChange = (event: MessageEvent) => { + setAtom(event.data); + }; + channel.addEventListener('message', handleChange); + return () => { + channel.removeEventListener('message', handleChange); + }; + }; + + const derivedAtom = atom], void>( + (get) => get(baseAtom), + (get, set, update: SetStateAction) => { + const currentValue = get(baseAtom); + const newValue = + typeof update === 'function' ? (update as (prev: T) => T)(currentValue) : update; + + isInitialized = true; + set(baseAtom, newValue); + setIndexedDBItem(key, newValue); + channel.postMessage(newValue); + } + ); + + return derivedAtom; +};