transmuter-store
Version:
Transmuter.js - simple state container store, fires events when property changes
119 lines (78 loc) • 4.13 kB
Markdown
# TransmuterStore
A store container that reacts to _transmutations_ of properties of the store itself by emitting events.
## Getting started
First, install `transmuter-store` via:
**NPM**
`npm install transmuter-store`
**Yarn**
`yarn add transmuter-store`
## Basic concept
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.
## How to use
In its simplest form, you can use `transmuter-store` like this:
```js
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];
```
## Limitations
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](https://github.com/facebook/immutable-js/).
**Plain JS, does _not_ trigger event**:
```js
// This does *not* trigger a TransmuterStore event unfortunately
store.state.items.push(4); // ❌
```
**Plain JS, does trigger event**:
```js
// This *does* trigger a TransmuterStore event
store.state.items = [...store.state.items, 4]; // ✅
```
**Using Immutable.js**
```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); // ✅
```
## Roadmap
- [ ] Watching nested objects, if possible.
- [ ] Watching items in arrays, if possible.
- [ ] Handle store property deletions
## Thanks
[Heydon Pickering](http://www.heydonworks.com/), for inspiring me with [Mutilator.js](https://gist.github.com/Heydon/9de1a8b55dd1448281fad013503a5b7a) to research and develop this library.
## License
TransmuterStore is [MIT-licensed](./LICENSE).