import { deepClone, isJsonEqual } from "@milaboratories/helpers"; import { computed, ref, watch, type ComputedGetter, type ComputedSetter, type ComputedRef, type WritableComputedRef, } from "vue"; /** * Alternative to `computed`, but triggering only on actual data changes. * Always `deep` as the plain `computed` is. */ export function computedCached(options: { get: ComputedGetter; set: ComputedSetter; }): WritableComputedRef; export function computedCached(getter: ComputedGetter): ComputedRef; export function computedCached( arg: | ComputedGetter | { get: ComputedGetter; set: ComputedSetter; }, ) { let getter: ComputedGetter; let setter: ComputedSetter | undefined = undefined; if (typeof arg === "function") { getter = arg; } else { getter = arg.get; setter = arg.set; } const cachedValue = ref(getter()); watch( getter, (newValue) => { if (!isJsonEqual(newValue, cachedValue.value)) { // `deepClone` is needed because in case some fields are patched the deep would be triggered, // but objects would be equal as the saved value was also patched cachedValue.value = deepClone(newValue); } }, { deep: true }, ); if (setter) { return computed({ get: () => cachedValue.value, set: setter, }); } else { return cachedValue; } }