feat: implement localstorage helper

master
Katja Lutz 2 years ago
parent 0b8bca9454
commit b23337fd59

@ -0,0 +1,85 @@
import { batch, createEffect, createSignal, onMount } from "solid-js";
import { createStore, reconcile } from "solid-js/store";
export const createLocalStore = function <T extends Record<string, any>>(
initState: T,
{
prefix = "app",
serializer = (v: any) => JSON.stringify(v),
deserializer = (v: any) => JSON.parse(v),
} = {}
) {
const [state, setState] = createStore(initState);
const [mounted, setMounted] = createSignal(false);
const localStorage = globalThis.localStorage;
if (localStorage) {
let mounts = 0;
let mounted_ = false;
const updating = {} as Record<string, any>;
const keys = Object.keys(state);
const changedBeforeMount = {} as Record<string, any>;
for (const key of keys) {
let storeKey = `${prefix}-${key}`;
let mountValue = localStorage.getItem(storeKey);
let initRun = true;
const [updatingCount, setUpdatingCount] = createSignal(0);
// TODO: Implement localStorage listener
createEffect(() => {
// During mounts we want to always run this effect even if the state value hasnt changed
// We need to run it always to reset updating[key]
updatingCount();
const isInitRun = initRun;
initRun = false;
const value = serializer(state[key]);
if (isInitRun && mountValue) {
return;
}
// If the key is getting mounted at the moment, we skip the localStorage set
if (updating[key]) {
updating[key] = false;
return;
}
if (!mounted_) {
changedBeforeMount[key] = true;
}
if (value === undefined) {
localStorage.removeItem(storeKey);
} else {
localStorage.setItem(storeKey, value);
}
});
onMount(() => {
if (!changedBeforeMount[key] && mountValue) {
updating[key] = true;
batch(function () {
setUpdatingCount(updatingCount() + 1);
setState(key as any, reconcile(deserializer(mountValue)));
});
}
mounts++;
mountValue = null;
if (mounts === keys.length) {
setMounted(true);
mounted_ = true;
}
});
}
}
return [state, setState, mounted] as [
typeof state,
typeof setState,
typeof mounted
];
};
Loading…
Cancel
Save