UNPKG

zustand-computed

Version:

A Zustand middleware to create computed states.

91 lines (90 loc) 3.17 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const isIterable = (obj) => Symbol.iterator in obj; const hasIterableEntries = (value) => ( // HACK: avoid checking entries type "entries" in value ); const compareEntries = (valueA, valueB) => { const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries()); const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries()); if (mapA.size !== mapB.size) { return false; } for (const [key, value] of mapA) { if (!Object.is(value, mapB.get(key))) { return false; } } return true; }; const compareIterables = (valueA, valueB) => { const iteratorA = valueA[Symbol.iterator](); const iteratorB = valueB[Symbol.iterator](); let nextA = iteratorA.next(); let nextB = iteratorB.next(); while (!nextA.done && !nextB.done) { if (!Object.is(nextA.value, nextB.value)) { return false; } nextA = iteratorA.next(); nextB = iteratorB.next(); } return !!nextA.done && !!nextB.done; }; function shallow(valueA, valueB) { if (Object.is(valueA, valueB)) { return true; } if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) { return false; } if (!isIterable(valueA) || !isIterable(valueB)) { return compareEntries( { entries: () => Object.entries(valueA) }, { entries: () => Object.entries(valueB) } ); } if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) { return compareEntries(valueA, valueB); } return compareIterables(valueA, valueB); } const computedImpl = (compute, opts) => (f) => { const optsKeys = !opts || !("keys" in opts) || opts.keys == null ? void 0 : opts.keys; const keysSet = optsKeys ? new Set(optsKeys) : void 0; function defaultShouldRecomputeFn(_, nextState) { if (!keysSet || nextState == null) return true; return Object.keys(nextState).some((k) => keysSet.has(k)); } const shouldRecomputeFn = opts && "shouldRecompute" in opts ? opts.shouldRecompute ?? defaultShouldRecomputeFn : defaultShouldRecomputeFn; return (set, get, api) => { const equalityFn = (opts == null ? void 0 : opts.equalityFn) ?? shallow; const computeAndMerge = (state) => { const computedState = compute({ ...state }); for (const k of Object.keys(computedState)) { if (equalityFn(computedState[k], state[k])) { delete computedState[k]; } } return { ...state, ...computedState }; }; const setWithComputed = (update, replace, ...args) => { set( (state) => { const updated = typeof update === "object" ? update : update(state); if (!(shouldRecomputeFn == null ? void 0 : shouldRecomputeFn(state, updated))) return { ...state, ...updated }; return computeAndMerge({ ...state, ...updated }); }, replace, ...args ); }; const _api = api; _api.setState = setWithComputed; const st = f(setWithComputed, get, _api); return Object.assign({}, st, compute(st)); }; }; const createComputed = computedImpl; exports.createComputed = createComputed;