Skip to content

Instantly share code, notes, and snippets.

@t3dotgg
Last active June 24, 2021 19:07
Show Gist options
  • Save t3dotgg/b558fd85e671395620d41fece5e2334c to your computer and use it in GitHub Desktop.
Save t3dotgg/b558fd85e671395620d41fece5e2334c to your computer and use it in GitHub Desktop.
A pattern for persisting and syncing an atom's value in Jotai
import { atom, useAtom } from "jotai";
const atomWithSyncedLocalStorage = <T>(key: string, initialValue: T) => {
const baseAtom = atom(initialValue);
baseAtom.onMount = (setValue) => {
const storageUpdateListener = (e: StorageEvent) => {
if (e.key === key) {
console.log("Updating instance of ", key, " remotely");
setValue(e.newValue ? JSON.parse(e.newValue) : undefined);
}
};
window.addEventListener("storage", storageUpdateListener);
const item = localStorage.getItem(key);
item && setValue(JSON.parse(item));
return () => window.removeEventListener("storage", storageUpdateListener);
};
const derivedAtom = atom(
(get) => get(baseAtom),
(get, set, update) => {
const nextValue =
typeof update === "function" ? update(get(baseAtom)) : update;
set(baseAtom, nextValue);
if (nextValue === undefined) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, JSON.stringify(nextValue));
}
}
);
return derivedAtom;
};
export const createSyncedStorageAtom = <T>(
STORAGE_KEY: string,
defaultValue: T
) => {
const syncedStorageAtom = atomWithSyncedLocalStorage<T>(
STORAGE_KEY,
defaultValue
);
const useSyncedStorageAtom = () => useAtom(syncedStorageAtom);
return [syncedStorageAtom, useSyncedStorageAtom] as [
typeof syncedStorageAtom,
typeof useSyncedStorageAtom
];
};
@t3dotgg
Copy link
Author

t3dotgg commented Jun 24, 2021

@dai-shi Good call outs! This was a rough rip from a React Native implementation I was porting, forgot to gut the async wrapper 😅

Just updated with that + the event listener cleanup!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment