feat: implement localstorage helper
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…
Reference in New Issue