A store container that reacts to transmutations of properties of the store itself by emitting events.
First, install transmuter-store
via:
NPM
npm install transmuter-store
Yarn
yarn add transmuter-store
A TransmuterStore consists of 3 things:
- The name of the store;
- The store itself, which could be an object with pre-existing properties as an initial state;
- The context on which to fire the events on.
By default, a TransmuterStore will fire events on a context element when a property of the store changes. This event is namespaced with the name of the store and the name of the property that changed. For example: if the store is named 'shed'
and the property that changed is called items
, then the event fired will be shed:items
.
How does this work, you ask? The magic of transmuter-store
lies in wrapping the store object in a Proxy
with a set
handler. The set
handler is called each time a property of the store is being added or changed. This handler then fires an event on the context element, specifying which property has changed.
transmuter-store
provides you with 2 things: the store container that fires the events, and a listener helper function (listen
) that eases the setting up of store listeners.
In its simplest form, you can use transmuter-store
like this:
import { TransmuterStore, listen } from 'transmuter-store';
// Set up an initial state for the store
const initialState = {
items: [1, 2, 3],
isMenuOpen: false
};
// Create a new store and apply the initial state object. Returns a store with name, context and state properties.
const store = new TransmuterStore('app', initialState);
console.log(store.name); // 'app'
console.log(store.context); // window
console.log(store.state); // State object Proxy, this is where the ✨ magic ✨ happens
// Listener function. This is called when a property changes with the name of the prop, the new value and the old value.
function logger(prop, value, oldValue, state) {
console.log('property:', prop);
console.log('new value:', value);
console.log('old value:', oldValue);
console.log('new state:', state);
}
// Add a store listener that listens to both the items and isMenuOpen properties and calls the above logger() function`
const listener = listen(store, ['items', 'isMenuOpen'], logger);
// Now when you change a property of the store, the change is logged using the listener function.
store.state.isMenuOpen = true;
// Add new items to array.
// ℹ️ See 'Limitations' below
store.state.items = [...store.state.items, 4];
As a set
handler of a Proxy
only watches direct properties of the object it wraps, changes to nested objects or items in arrays won't propagate to the set
handler. Use array/object destructuring for this and assigning the new result directly to the store, or use something like Immutable.js.
Plain JS, does not trigger event:
// This does *not* trigger a TransmuterStore event unfortunately
store.state.items.push(4); // ❌
Plain JS, does trigger event:
// This *does* trigger a TransmuterStore event
store.state.items = [...store.state.items, 4]; // ✅
Using Immutable.js
import { TransmuterStore } from 'transmuter-store';
import { List } from 'immutable';
// Set up state
const initialState = {
items: List([1, 2, 3]) // Use an Immutable List
};
// Set up store
const store = new TransmuterStore('store', initialState);
// Returns a new List containing the added item and assign it to the store.
store.state.items = store.state.items.push(4); // ✅
- Watching nested objects, if possible.
- Watching items in arrays, if possible.
- Handle store property deletions
Heydon Pickering, for inspiring me with Mutilator.js to research and develop this library.
TransmuterStore is MIT-licensed.