A library to manage application state, heavily inspired by mobx-state-tree
setState)
I was disappointed with all the current state management solutions. Then I found mobx-state-tree, which seemed like a godsend to me (ok not really, but I liked the concept), but it was pretty big in terms of file size (mobx alone is big: 16.5kB). So I thought it's surely possible to make a smaller version of it, that's how this started. And after 2 failed attempts I finally got something that works well
$ npm i parket
// ES6 import { model } from 'parket'; // CJS const { model } = require('parket');
Note: This library uses Proxies and Symbols. Proxies cannot be fully polyfilled so you have to target modern browers which support Proxies.
import { model } from 'parket'; // model returns a "constructor" function const Person = model('Person', { // name is used internally for serialization initial: () => ({ firstname: null, lastname: null, nested: null, }), actions: (state) => ({ setFirstName(first) { state.firstname = first; // no set state, no returns to merge, it's reactive™ }, setLastName(last) { state.lastname = last; }, setNested(nested) { state.nested = nested; }, }), views: (state) => ({ fullname: () => `${state.firstname} ${state.lastname}`, // views are computed properties }), });// merge an object with the initial state const instance = Person({ firstname: 'Tom' });
// you can subscribe to actions, patches (state updates) and snapshots (full state after actions) const unsubscribe = instance.onSnapshot(console.log);
// you can unsubscribe by calling the function returned by the listener // unsubscribe();
instance.setLastName('Clancy');
// views turn into cached getters console.log(instance.fullname); // 'Tom Clancy'
// nested models also bubble up events to the parent instance.setNested(Person());
instance.nested.setFirstName('wow');
// you can get a snapshot of the state at any time // { firstname: 'Tom', lastname: 'Clancy', nested: { firstname: 'wow', lastname: null, nested: null } } console.log(instance.getSnapshot());
const Async = model('Async', { initial: () => ({ loading: false, result: null, }), actions: (self) => ({ async doSomethingAsync() { // actions can be async, parket doesn't care self.loading = true; self.result = await somethingAsync(); // be aware that you should handle errors self.loading = false; }, }), });
import { Component } from 'preact'; import { observe, connect, Provider } from 'parket/preact'; // or 'parket/react'// observe keeps the component updated to models in the prop @observe class Observed extends Component { render({ person }) { // if you're using react, props don't get passed to render so you have to use
const {person} = this.props;
return (); } }{person.fullname}
// connect inserts the store/instance into props @connect class Person extends Component { render({ store }) { // if you're using react, props don't get passed to render so you have to use
const {store} = this.props;
return (); } }{store.fullname}
// Provider adds an instance to the context const root = () => (
);
function Observed({ person }) { useObserved(person);return (
); }{person.fullname}
function Person() { const store = useStore();
return (
); }{store.fullname}
// Provider adds an instance to the context const root = () => (
);