@classflow/mobx-decorators

    2.2.6 • Public • Published

    MobX decorators

    Several helper MobX decorators

    Build Status Coverage Status

    1. Installation
    2. Decorators
    1. Changelog

    Installation

    npm install --save mobx-decorators

    You also should use some transpiler (like babel).

    npm install --save-dev babel-plugin-transform-decorators-legacy

    Decorators

    @setter

    @setter
    @setter(name)
    @setter(name, constValue)
    @setter(transformFn: value =>)
    @setter(name, transformFn: value =>)

    Create setter for property with setProperty or custom name.

    If constValue provided this value will be set every time setter called. You can also provide transform function.

    With transformFn function you can change value that will be set.

    import {observable} from 'mobx'
    import {setter} from 'mobx-decorators'
    class User {
      @setter
      @observable
      loggedIn = false;
    }
     
    const user = new User();
    user.setLoggedIn(true); // user.loggedIn = true
    class User {
      @setter('updateLoggedIn')
      @observable
      loggedIn = false;
    }
     
    const user = new User();
    user.updateLoggedIn(true); // user.loggedIn = true
    class User {
      @setter('login', true)
      @setter('logout', false)
      @observable
      loggedIn = false;
    }
     
    const user = new User();
    user.login(); // user.loggedIn = true
    user.logout(); // user.loggedIn = false
    class User {
      @setter(value => value && value.toUpperCase())
      @observable
      name;
    }
     
    const user = new User();
    user.setName('Alice'); // user.name = 'ALICE'

    @toggle

    @toggle
    @toggle(name)

    Toggle boolean property (property = !property).

    import {observable} from 'mobx'
    import {toggle} from 'mobx-decorators'
    class User {
      @toggle
      @observable
      loggedIn = false;
    }
     
    const user = new User();
    user.toggleLoggedIn(); // user.loggedIn = !user.loggedIn
    class User {
      @toggle('swapLoggedIn')
      @observable
      loggedIn = false;
    }
     
    const user = new User();
    user.swapLoggedIn(); // user.loggedIn = !user.loggedIn

    @observe

    @observe(onChanged: change =>)
    @observe(onChanged: change =>, invokeBeforeFirstAccess)

    Don't work with TypeScript yet (sorry)

    onChanged will be called after property change.

    If invokeBeforeFirstAccess is true handler will be called one time before property first access (set or get).

    More info can be found in mobx docs

    import {observable} from 'mobx'
    import {observe} from 'mobx-decorators'
    class User {
      @observe(change => console.log(change.newValue))
      @setter
      @observable
      loggedIn = false;
    }
     
    const user = new User();
    user.setLoggedIn(true); // console.log(true)
    class User {
      @observe(change => console.log(change.newValue), true)
      @setter
      @observable
      loggedIn = false;
    }
     
    const user1 = new User();
    const loggedIn = user.loggedIn; // console.log(false)
    user1.setLoggedIn(true); // console.log(true)
     
    const user2 = new User();
    user2.setLoggedIn(true); // console.log(false)
                             // console.log(true)

    @intercept

    @intercept(onWillChange: change =>)

    Don't work with TypeScript yet (sorry)

    onWillChange will be called before property change. You can replace value or cancel change in handler.

    More info can be found in mobx docs

    import {observable} from 'mobx'
    import {intercept} from 'mobx-decorators'
    class User {
      @intercept(change => {
        change.newValue = 999;
        return change;
      })
      @setter
      @observable
      loginCount = 0;
    }
     
    const user = new User();
    user.setLoginCount(1); // user.loginCount = 999;
    class User {
      @intercept(change => null)
      @setter
      @observable
      loginCount = 0;
    }
     
    const user = new User();
    user.setLoginCount(1); // user.loginCount = 0;

    @save

    @save
    @save({
      storage = defaultStorage(),
      storeName = store.storeName,
      transform = item => item,
      onLoaded = (store, property, value) => {},
      onSaved = (store, property, value) => {},
      onInitialized = (store, property, value) => {},
    })

    createSaveDecorator(baseOptions={})

    Don't work with TypeScript yet (sorry)

    @save decorator helps save and load observable value to/from permanent storage. Keep in mind @save is lazy decorator and loading will be started only after first property access. If you change property before or during loading than restored value will be ignored.

    onLoaded callback will be called only if value is loaded from storage.
    onSave will be called after saving.
    onInitialized will be called after loading attempt independent of the result.

    Because values saved as json in some cases (Date for example) you should provide transform function (see example with date).

    You must define storeName property in store (see examples) or pass it as option.

    Default storage is localStorage for browser, AsyncStorage for React Native and memory for other platforms. You can specify you own (localForage for example) by storage option. Storage must realize simple interface (functions are async or must return Promise):

    const MyStorage = {
      async getItem(key) {
        // return item
      },
      async setItem(key, value) {
        // save item
      }
    }

    If you need to pass the same options (storage for example) to @save decorator of several properties than you can use createSaveDecorator function.

    import {observable} from 'mobx'
    import {save, createSaveDecorator} from 'mobx-decorators'
    class User {
      storeName = 'user';
     
      @save
      @observable
      loginCount = 0;
    }
     
    const user = new User();
    console.log(user.loginCount); // 0
    // @save will try to load loginCount from storage but
    // loading is async (!) so value is still 0 here
    class User {
      storeName = 'user';
     
      // storage contains 999 for loginCount property
      @save({
        onInitialized: (store, property, value) => {
          console.log(property, value); // 'loginCount', 999
          console.log(store.loginCount); // 999
        },
        onLoaded: (store, property, value) => {
          console.log(property, value); // 'loginCount', 999
          console.log(store.loginCount); // 999
        },
        onSave: (store, property, value) => {
          console.log(property, value); // 1000
        }
      })
      @setter
      @observable
      loginCount = 0;
    }
     
    const user = new User();
    console.log(user.loginCount); // 0
     
    // after some time
    console.log(user.loginCount); // 999
     
    // after some time
    user.setLoginCount(1000); // 1000 will be saved to storage
    class User {
      @save({
        storeName: 'user',
      })
      @observable
      loginCount = 0;
      
      @save({
        storeName: 'group',
      })
      @observable
      group = 'noname';
    }
     
    const user = new User();
    console.log(user.loginCount); // 0
    console.log(user.group); // 'noname'
    class User {
      storeName = 'user';
     
      @save({
        transform: value => {
          console.log(value); // "2017-03-15T19:20:24.638Z"
          return new Date(value)
        },
      })
      @observable
      lastLogin = new Date(2000, 1, 1);
    }
     
    const user = new User();
    console.log(user.lastLogin);
    const save = createSaveDecorator({
      storage: MyOwnStorage,
      storeName: 'user',
    });
     
    class User {
      @save
      @observable
      loginCount = 0;
      
      @save
      @observable
      name = 'noname';
    }
     
    const user = new User();
    console.log(user.loginCount);
    const save = createSaveDecorator({
      storage: MyOwnStorage,
      storeName: 'user',
    });
     
    class User {
      @save({
        onInitialized: () => console.log('initialized')
      })
      @observable
      loginCount = 0;
      
      @save
      @observable
      name = 'noname';
    }
     
    const user = new User();
    console.log(user.loginCount);

    @allObservable

    @allObservable
    @allObservable({
      only,
      except = [],
    })

    Class decorator that makes all properties observable. Use only for whitelisting properties and except for blacklisting.

    import {allObservable} from 'mobx-decorators'
    @allObservable
    class User {
      name = 'unknown';
      loginCount = 0;
    }
    @allObservable({only: ['loginCount']})
    class User {
      name = 'unknown';
      loginCount = 0;
    }
    @allObservable({except: ['name']})
    class User {
      name = 'unknown';
      loginCount = 0;
    }

    Changelog

    2.2.4

    • all callbacks called in store context now

    2.2.3

    • fix @observe, @intercept and @save may not work with extending

    2.2.1

    • @allObservable: fix getter and setter for observable was not defined

    2.2.0

    • @allObservable
    • @save, @observe and @intercept can be defined after @observable now
    • decorators return configurable properties now

    2.1.1

    • transpiling with es2015 preset now

    2.1.0

    • @setter: you can provide transform function now
    class User {
      @setter(value => value && value.toUpperCase())
      @observable
      name;
    }
     
    const user = new User();
    user.setName('Alice'); // user.name = 'ALICE'
    • @save, @createSaveDecorator
    • transpiled version

    2.0.0

    • Adopting to mobx3

    @observe callback receive change argument now ( more info )

    Install

    npm i @classflow/mobx-decorators

    DownloadsWeekly Downloads

    22

    Version

    2.2.6

    License

    WTFPL

    Last publish

    Collaborators

    • mav
    • scott.johnson.pro
    • andrew.burtnett
    • brooks.p.pro
    • evgeny.m