feat(app): rought our url persistence

This commit is contained in:
rektdeckard
2023-08-21 00:31:00 -06:00
committed by Tobias Fried
parent 2bcf098d1d
commit 6db9a08f7f
6 changed files with 266 additions and 28 deletions

View File

@@ -0,0 +1,84 @@
import { useCallback, ReactNode } from "react";
import { DefaultValue } from "recoil";
import { ReadItem, WriteItems, ListenToItems, RecoilSync } from "recoil-sync";
import { STORAGE_KEY } from ".";
const DEFAULT_VALUE = new DefaultValue();
export default ({ children }: { children: ReactNode }) => {
const read: ReadItem = useCallback((itemKey) => {
if (typeof document === "undefined") return DEFAULT_VALUE; // SSR
const item = localStorage.getItem(itemKey);
let parsed: unknown;
try {
parsed = item === null ? DEFAULT_VALUE : parseJSON(item);
} catch {
parsed = DEFAULT_VALUE;
console.warn({ itemKey, item }, "parseJSON failed");
}
return parsed;
}, []);
const write: WriteItems = useCallback(({ diff }) => {
if (typeof document === "undefined") return; // SSR
for (const [key, value] of diff) {
if (value instanceof DefaultValue) {
localStorage.removeItem(key);
} else {
// reasons for setItem to fail: https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem#exceptions
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (err) {
console.warn({ err, key, value }, "localStorage.setItem failed");
}
}
}
}, []);
const listen: ListenToItems = useCallback(
({ updateItem, updateAllKnownItems }) => {
const onStorage = (event: StorageEvent) => {
// ignore clear() calls
if (event.storageArea === localStorage && event.key !== null) {
let parsed: unknown;
try {
parsed =
event.newValue === null
? DEFAULT_VALUE
: parseJSON(event.newValue);
} catch {
parsed = DEFAULT_VALUE;
console.warn({ event }, "parseJSON failed");
}
updateItem(event.key, parsed);
}
};
window.addEventListener("storage", onStorage);
return () => window.removeEventListener("storage", onStorage);
},
[]
);
return (
<RecoilSync
storeKey={STORAGE_KEY}
read={read}
write={write}
listen={listen}
>
{children}
</RecoilSync>
);
};
function parseJSON(value: string): unknown {
return value === "undefined" ? undefined : JSON.parse(value);
}