UNPKG

nucleux

Version:

Simple, atomic hub for all your React application's state management needs. No providers, no boilerplate, just state that works.

104 lines (103 loc) 3.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Atom = void 0; const es6_1 = __importDefault(require("fast-deep-equal/es6")); const nanoid_1 = require("nanoid"); class Atom { _value; _initialValue; subscribers = new Map(); persistence; memoization; constructor(initialValue, options) { this._value = initialValue; this._initialValue = initialValue; this.persistence = options?.persistence; this.memoization = options?.memoization; this.subscribe = this.subscribe.bind(this); this.unsubscribe = this.unsubscribe.bind(this); this.hydrate(); } async hydrate() { if (this.persistence) { const { persistKey, storage = localStorage } = this.persistence; const rawPersistedValue = await storage.getItem(persistKey); if (rawPersistedValue) { try { const persistedValue = JSON.parse(rawPersistedValue); this.value = persistedValue; } catch (error) { console.error(`Could not parse value ${rawPersistedValue} for ${persistKey}. Error:`, error); } } else { // fire-and-forget storage.setItem(persistKey, JSON.stringify(this.value)); } } } shouldSkipUpdate(newValue) { const { type, compare } = this.memoization || { type: 'shallow' }; if (type === 'deep') { return (0, es6_1.default)(newValue, this.value); } if (type === 'custom') { return compare ? compare(newValue, this.value) : newValue === this.value; } return newValue === this.value; } notifySubscribers(newValue, previousValue) { for (const [, subscriber] of this.subscribers) { try { if (subscriber.callback.length === 2) { subscriber.callback(newValue, previousValue); } else { subscriber.callback(newValue); } } catch (error) { console.error('Error in atom subscriber:', error); } } } get initialValue() { return this._initialValue; } get value() { return this._value; } set value(newValue) { if (this.shouldSkipUpdate(newValue)) { return; } const previousValue = this._value; this._value = newValue; if (newValue !== undefined && this.persistence) { const { persistKey, storage = localStorage } = this.persistence; // fire-and-forget storage.setItem(persistKey, JSON.stringify(newValue)); } this.notifySubscribers(newValue, previousValue); } subscribe(callback, immediate = false) { const subId = (0, nanoid_1.nanoid)(); this.subscribers.set(subId, { callback }); if (immediate) { callback(this.value); } return subId; } unsubscribe(subId) { if (!this.subscribers.has(subId)) { console.warn(`Subscriber ${subId} not found`); return false; } return this.subscribers.delete(subId); } } exports.Atom = Atom;