UNPKG

mutable-store

Version:

a mutable state management library for javascript

174 lines (126 loc) 4.39 kB
const documentation = ` # Mutable Store A lightweight, reactive store pattern for managing application state with simplicity and full control. --- ## 📦 Store The Store function wraps your object and turns it into a reactive store where: - All methods that start with `set_` are considered **mutative**. - A global `subscribe(fn)` method is provided to listen for changes. - It auto-subscribes to internal stores (i.e., nested stores created using `Store`). - All function and internal store references are made **read-only**. - Non-mutative methods (like `get_`, `action_`) are untouched unless you mutate state directly inside them. --- ## ✅ Features - Lightweight & framework-agnostic. - Built-in subscription system. - Auto-nested-store detection and tracking. - Only mutative functions (`set_*`) trigger updates. - Read-only enforcement for function and nested store props. - Controlled and explicit design: mutations only when intended. --- ## 🔧 API ### `Store(mutableState: object)` Wrap your state and methods in a store. #### Example: import {Store} from "mutable-store"; ```ts const counter = Store({ count: 0, set_increment() { this.count++; }, get_count() { return this.count; } }); counter.subscribe(() => { console.log("State changed!"); }); counter.set_increment(); // Triggers subscriber console.log(counter.get_count()); // 1 ``` --- ### 💡 Conventions | Prefix | Purpose | |-------------|----------------------------------------------| | `set_*` | Used to **mutate** the store. Triggers updates. | | `get_*` | Used to **read** state. Does **not** trigger updates. | | `action_*` | Used to **orchestrate** multiple getters/setters. Can be async or sync. Does **not** directly mutate state unless via a `set_*`. | > ⚠️ All mutative methods **must** start with `set_` to trigger updates. --- ### 🔁 Nested Stores You can pass nested stores as part of your store object: This lets you use existing store logic as a substore. ```ts const loadingState = Store({ isLoading : false, set_isLoading(isLoading) { this.isLoading = isLoading; } }); const usersStore = Store({ users: [], loadingState, // Nested store action_fetchUsers() { this.loadingState.set_isLoading(true); fetch("/users").then(() => { this.loadingState.set_isLoading(false); }); } }); const photosStore = Store({ photos: [], loadingState, // Nested store action_fetchPhotos() { this.loadingState.set_isLoading(true); fetch("/photos").then(() => { this.loadingState.set_isLoading(false); }); } }); // Both stores use the same sub store usersStore.action_fetchUsers(); // Triggers parent store subscription photosStore.action_fetchPhotos(); // Triggers parent store subscription ``` --- ### inheritance You can create a store from a class that inherts props or methods from another class. This helps you to create a store from a class that extends another class. ```ts class Counter { count = 0; set_increment() { this.count++; } } class Counter2 extends Counter { city = "New York"; set_city(newCity:string) { this.city = newCity; this.set_increment(); } } const counter = Store(new Counter2()); console.log(counter); // {count: 0, city: "New York", set_increment: ƒ, set_city: ƒ} counter.subscribe(() => { console.log("Counter changed!"); }); counter.set_city("London"); // Triggers parent store subscription ``` ### 🧩 Internals - All functions and nested stores are made **non-configurable and non-writable**. - `subscribe(fn)`: Adds a listener to the store. - `___thisIsAMutableStore___: true`: Internal flag to identify nested stores. - `___version___: 1`: Reserved for future enhancements. --- ### ⚠️ Limitations & Warnings - `subscribe` is a **reserved key** do not define it inside your store object. - Mutations must occur **only** inside `set_*` methods. - You **cannot add** new properties to the store after creation (due to `Object.preventExtensions`). - Deep reactivity is **manual** this is intentional to keep it lightweight and predictable. --- ## ✅ Summary This store is: - Explicit. - Predictable. - Reactive when and only when you want it to be. - Simple enough for small apps, yet composable for large ones. ---