Skip to content

Commit

Permalink
remove computed side-effect and simplify user scoped ref
Browse files Browse the repository at this point in the history
allow to sync existing ref
  • Loading branch information
ElectronicBlueberry committed Dec 12, 2024
1 parent 36de47d commit ba0f0d4
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 38 deletions.
39 changes: 23 additions & 16 deletions client/src/composables/persistentRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,44 @@ function parse<T>(value: string, type: "string" | "number" | "boolean" | "object
});
}

export function usePersistentRef(key: string, defaultValue: string): Ref<string>;
export function usePersistentRef(key: string, defaultValue: number): Ref<number>;
export function usePersistentRef<T>(key: string, defaultValue: T): Ref<T>;
export function usePersistentRef<T extends string | number | boolean | object | null>(
key: string,
defaultValue: T
): Ref<T> {
const storageSyncedRef = ref(defaultValue) as Ref<T>;

export function syncRefToLocalStorage<T>(key: string, refToSync: Ref<T>) {
const stored = window.localStorage.getItem(key);

const sync = () => {
const stringified = stringify(refToSync.value);
window.localStorage.setItem(key, stringified);
};

if (stored) {
try {
storageSyncedRef.value = parse(stored, typeof defaultValue as "string" | "number" | "boolean" | "object");
refToSync.value = parse(stored, typeof refToSync.value as "string" | "number" | "boolean" | "object");
} catch (e) {
console.error(`Failed to parse value "${stored}" from local storage key "${key}". Resetting key`);
window.localStorage.removeItem(key);
sync();
}
} else {
const stringified = stringify(storageSyncedRef.value);
window.localStorage.setItem(key, stringified);
sync();
}

watch(
() => storageSyncedRef.value,
() => refToSync.value,
() => {
const stringified = stringify(storageSyncedRef.value);
window.localStorage.setItem(key, stringified);
sync();
},
{ deep: true }
);
}

export function usePersistentRef(key: string, defaultValue: string): Ref<string>;
export function usePersistentRef(key: string, defaultValue: number): Ref<number>;
export function usePersistentRef<T>(key: string, defaultValue: T): Ref<T>;
export function usePersistentRef<T extends string | number | boolean | object | null>(
key: string,
defaultValue: T
): Ref<T> {
const storageSyncedRef = ref(defaultValue) as Ref<T>;

syncRefToLocalStorage(key, storageSyncedRef);

return storageSyncedRef;
}
36 changes: 14 additions & 22 deletions client/src/composables/userLocalStorage.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { computed, customRef, type Ref, ref } from "vue";
import { watchImmediate } from "@vueuse/core";
import { type Ref, ref } from "vue";

import { type AnyUser } from "@/api";

import { useHashedUserId } from "./hashedUserId";
import { usePersistentRef } from "./persistentRef";
import { syncRefToLocalStorage } from "./persistentRef";

/**
* Local storage composable specific to current user.
Expand All @@ -13,27 +14,18 @@ import { usePersistentRef } from "./persistentRef";
export function useUserLocalStorage<T>(key: string, initialValue: T, user?: Ref<AnyUser>) {
const { hashedUserId } = useHashedUserId(user);

let refSyncedRawValue = initialValue;
const refToSync = ref(initialValue);
let hasSynced = false;

const storedRef = computed(() => {
if (hashedUserId.value) {
return usePersistentRef(`${key}-${hashedUserId.value}`, refSyncedRawValue);
} else {
return ref(initialValue);
watchImmediate(
() => hashedUserId.value,
() => {
if (hashedUserId.value && !hasSynced) {
syncRefToLocalStorage(`${key}-${hashedUserId.value}`, refToSync);
hasSynced = true;
}
}
});
);

const currentValue = customRef((track, trigger) => ({
get() {
track();
return storedRef.value.value;
},
set(newValue) {
storedRef.value.value = newValue;
refSyncedRawValue = newValue as T;
trigger();
},
}));

return currentValue;
return refToSync;
}

0 comments on commit ba0f0d4

Please sign in to comment.