/Magicist

Extra simple state manager

Primary LanguageJavaScriptMIT LicenseMIT

Magicist logo

Magicist

CircleCI Test Coverage Bundle size PRs Welcome License

Extra simple state manager.

No need to think about details. Just write code

Table of Contents

Advantages

  • Zero-dependency
  • Tiny bundle size (1 KB gzipped)
  • Boilerplate free
  • React bindings out of the box
  • Async actions management out of the box
  • Only point changes (you no longer need to reduce the state)
  • With Magicist you don't need to normalize your data. This makes the library very suitable for very complex domain models
  • No need classes, decorators
  • No need immutable data structures

Installation

Via yarn

yarn add magicist

Via npm

npm install magicist --save

Introduction

Magicist works by simple cycle, see illustration below

Magicist's concept

Examples

Increment/decrement

import React from 'react';
import {createStore} from "magicist";
import {useStore} from "magicist";

export const counterStore = createStore({
    count: 0,
    increment: function () {
        this.count++;
    },
    decrement: function () {
        this.count--;
    },
    reset: function() {
        this.count = 0;
    }
});

const Counter = () => {
    let {count, increment, decrement, reset} = useStore(counterStore);

    return (
        <>
            <div>Counter {count}</div>
            <button onClick={increment}>+</button>
            <button onClick={decrement}>-</button>
            <button onClick={reset}>Reset</button>
        </>
    );
};

Demo

Basic

Edit magicist-counter-example

API

createStore

createStore(model, middlewares) Create a store object that holds the state tree.

Arguments

  1. model: Object
  2. middlewares: Array<(model: Object, func: (any) => any, args: Array) => void>

Returns

Store object that holds the state tree.

Example

const store = createStore({
    someData: 100
});

middlewares

These are functions that intercept actions. Middlewares are will be called before running the store functions.

Middleware function arguments:

  1. model: Model
  2. func: Function
  3. args: arguments to be passed in called function

Example

function logger(model, func, args) {
    console.log(model); // {someData: 100, manipulateData: (...)}
    console.log(func); // ƒ (receivedData) { return this.someData / receivedData; }
    console.log(args); // [100]
}

const middlewares = [logger];

const store = createStore({
    someData: 100,
    manipulateData: function(receivedData) {
        return this.someData / receivedData;
    }
}, middlewares);

store.getModel().manipulateData();

watch

watch(watcher) Triggers the callback when store is updated

Arguments

  1. watcher: (model: Model) => void

Returns

disposer function, which can be used to dispose of the watcher when you no longer need it.

Example

const globalStore = createStore({
    count: 0,
    increment: function () {
        this.count++;
    }
});

const watcher = model => console.log(model);
const disposer = globalStore.watch(watcher); // { count: 1, increment: (...) }

globalStore.getModel().increment();
disposer(); // unsubscribe from updates

watchProp

watchProp(propName, watcher) Triggers the callback when store's prop is updated

Arguments

  1. watcher: (oldValue, newValue) => void

Returns

disposer function, which can be used to dispose of the watcher when you no longer need it.

Example

const globalStore = createStore({
    count: 0,
    increment: function () {
        this.count++;
    }
});

const watcher = (oldValue, newValue) => console.log(oldValue, newValue);
const disposer = globalStore.watchProp('count', watcher); // 0, 1

globalStore.getModel().increment();
disposer(); // unsubscribe from updates

useStore

useStore(store) Creates hook function, which subscribe to watcher, that observes changes in current store, so when recording results, the component will update automatically.

Arguments

  1. store: Store (created by createStore)

Returns

Model

Example

let model = useStore(store);

What will Magicist react to?

Magicist reacts to any existing observable property that is read during the execution of a tracked function.

Contributing

  • Feel free to send pull requests.
  • Use yarn test to run the basic test suite.