Have ideas to improve npm?Join in the discussion! »

    parket
    TypeScript icon, indicating that this package has built-in type declarations

    0.6.0 • Public • Published



    • Small (~1.5KB)
    • Immutable from the outside, mutable in actions
    • Reactive (state emits updates without explicit calls to i.e. setState)
    • Modular (you can nest models inside each other)

    Why?

    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

    Installation

    $ npm i parket
    
    // ES6
    import { model } from 'parket';
    // CJS
    const { model } = require('parket');

    Usage

    Note: This library uses Proxies and Symbols. Proxies cannot be fully polyfilled so you have to target modern browers which support Proxies.

    Basic example

    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());

    Async example

    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;
        },
      }),
    });

    preact / react

    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 (
          <div>
            <h1>{person.fullname}</h1>
          </div>
        );
      }
    }
     
    // 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 (
          <div>
            <h1>{store.fullname}</h1>
          </div>
        );
      }
    }
     
    // Provider adds an instance to the context
    const root = () => (
      <Provider store={instance}>
        <div id="app">
          <Person />
          <Observed person={instance} />
        </div>
      </Provider>
    );

    preact / react hooks

    function Observed({ person }) {
      useObserved(person);
     
      return (
        <div>
          <h1>{person.fullname}</h1>
        </div>
      );
    }
     
    function Person() {
      const store = useStore();
     
      return (
        <div>
          <h1>{store.fullname}</h1>
        </div>
      );
    }
     
    // Provider adds an instance to the context
    const root = () => (
      <Provider store={instance}>
        <div id="app">
          <Person />
          <Observed person={instance} />
        </div>
      </Provider>
    );

    Credits

    License

    MIT © hrmny.sh

    Install

    npm i parket

    DownloadsWeekly Downloads

    7

    Version

    0.6.0

    License

    MIT

    Unpacked Size

    129 kB

    Total Files

    48

    Last publish

    Collaborators

    • avatar