vistate
v0.2.2
Published
Recordable state container. OOP style
Downloads
2
Maintainers
Readme
Vistate: smart actionable models instead of one big state container
state of project: not ready for use in production YET. But keep watching.
Assumptions
- Action dispatching is conceptually the same as method call
object.dispatch({type: 'increment', payload: 30});
is conceptually the same as:
object.increment(30);
We just have some object (e.g. model, store, entity etc.) and we send messages to it (It is nothing new, it's just the old school OOP.).
But method calling requires less boilerplate so the approach object.increment(30)
is preffered to the first one.
Sometimes we just need intelligent models which encapsulate both state and logic
Sometimes we need whole hierarchy of models
[ -------------------------- Todo application -------------------------- ] [ TodoList ] [ TodoList ] [ TodoList ] | | | | | | | | | [Todo] [Todo] [Todo] [Todo] [Todo] [Todo] [Todo] [Todo] [Todo] ^ we like to send an action to this Todo
And it should be possible to send action to the specific model and work on model level (not store or observable property level). In Vistate the most important thing is a model.
Logic of dispatching the action and updating the state should be hidden from user. There is some kind of magic behind scene. When user calls
counter.increment(30)
this could be dispatched in anyway possible. Action could be automatically recorded, previous state could be saved, subcribers could be notified. These things work automatically behind scenes, mainly in middleware systems. Systems are assigned to the models during creation.
Projects should be easily debuggable and inspectable (there will be Dev Tools for Vistate soon...)
Built-in solution for side-effects and asynchronicity (currently there are transactions for this purpose).
Embracing inspiration
Vistate takes inspiration from Redux, MVC, Smalltalk, SAM pattern, CQRS, event sourcing, DDD, Entity Component System, Vue, Vuex, Mobx, React, Django, Backbone, Rx, Redux Saga and many other things.
This means that although there could be some similarities with many other libraries and approaches but Vistate is not bound to one philosophy but it's inspired by many.
Immutability / mutability is an implementation detail.
This framework started as being mutable. It promoted mutation of models directly in the action handlers:
.... increment(state) { state.value += 1; } ....
Now there is ongoing transition to use immutable data, but the API stays the same. In current implementation action handlers just don't receive real state but only proxy objects. When an action handler calls
state.value += 1;
This mutation is only recorded (not yet applied). This is the model that really applies these mutations. This is inspired by SAM pattern and its "proposed values". But the difference is that in Vistate there is a little bit syntax sugar to it. To achieve this a little library called transmutable was created. You can try it yourself.
for examples of use check test cases because they are most recent source of truth: https://github.com/hex13/enter-ghost/blob/master/packages/vistate/test/stateContainerSpec.js
API is not stable yet so there can be breaking changes.
Latest breaking changes:
- no data() method in Transaction.
- transaction methods return promise
Examples of use:
const assert = require('assert');
const { Model } = require('vistate');
class Example extends Model {
$initialState() {
return {value: 100};
}
inc(state, amount) {
state.value += amount;
}
}
const model = new Example();
model.$subscribe(() => {
console.log("update your view here");
console.log("current state:", model.state);
});
// notice that each call will trigger handler passed in `subscribe`
model.inc(100);
model.inc(200);
assert.equal(model.state.value, 400);
console.log("UNDO!");
// this uses event sourcing under the hood:
model.$undo();
assert.equal(model.state.value, 200);