Skip to content

Latest commit

 

History

History
371 lines (310 loc) · 8.94 KB

README.md

File metadata and controls

371 lines (310 loc) · 8.94 KB

JStore - simple, flexible, reactive store

Install

yarn add @jashkasoft/rx-jstore

JStore

  • initValue only condition check if operator

  • clone with last value only if jstore has config property initial value

  • formatters run with priority by index ( prev value passed to next formatter ) return last formatted value

  • middleware

  • snapshot ( current state if exists )

  • Base: formatters: - to number - to string - trim storage: - simple storage ( in memory )

Examples
  • Initial value

    import { JStore } from '@jashkasoft/rx-jstore';
    
    const store = new JStore<string>({
         initValue: 'string',
    });
    
    console.log('snapshot with value', store.snapshot());
    
    const subscription = store.subscribe((value: string) => {
        console.log('store', value); // string and after new str
    });
    
    store.dispatch('new str');
    
    // complete store & unsubscribe
    store.destroy(subscription);
  • Custom input & output formatters ( Formatters are Observable )

    import { JStore, TrimFormatter, FormatterInterface } from '@jashkasoft/rx-jstore';   
    import { of, Observable } from 'rxjs';
    
    class TrimFormatter implements FormatterInterface {
       public transform(str: string): Observable<string> {
         return of(str.trim());
       }
     }
    class StrEndOutputFormatter implements FormatterInterface {
       public transform(str: string): Observable<string> {
         return of(str + ' end of string');
       }
     }
    const store = new JStore<string>({
         inputFormatters: [
            new TrimFormatter()
         ],
         outputFormatters: [
            new StrEndOutputFormatter()
         ]
    });
    const subscription = store.subscribe((value: string) => {
        console.log('store', `'${value}'`); // 'new str end of string'
    });
    store.dispatch('      new str   ');
    store.destroy(subscription);
  • Custom storage

    import { JStore, StorageInterface, FormatterInterface } from '@jashkasoft/rx-jstore';   
    import { of, Observable } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    interface CustomObject {
       name: string;
       id: number;
     }
    
    class LocalStorage<T> implements StorageInterface<T> {
      constructor(private token: string = 'store') {
      }
    
      public get(): Observable<any> {
        return of(localStorage.getItem(this.token));
      }
    
      public set(value: any): Observable<T | null> {
        localStorage.setItem(this.token, value);
        return of(value);
      }
    
      public clear(): Observable<T | null> {
        localStorage.removeItem(this.token);
        return of(null);
      }
    
    }
    
    class StringToJSONFormatter implements FormatterInterface {
      public transform(str: string): Observable<any> {
        return of(JSON.parse(str));
      }
    }
    
    class JSONToStringFormatter implements FormatterInterface {
      public transform(json: any): Observable<string> {
        return of(json)
          .pipe(
            map(json => JSON.stringify(json))
          );
      }
    }
     
    const store = new JStore<CustomObject>({
      storage: new LocalStorage<CustomObject>(),
      inputFormatters: [
        new JSONToStringFormatter()
      ],
      outputFormatters: [
        new StringToJSONFormatter()
      ]
    });
     
    const subscription = store.subscribe((value: CustomObject) => {
      console.log('store', value);
    });
    
    store.dispatch({
      name: 'name',
      id: 2
    });
    
    store.destroy(subscription);
  • Strict storage checking

    const store = new JStore<any>({
        strictTypeCheck: true,
        initValue: '13'
    });
    
    // ok, string type
    store.dispatch('Hello, World!');
    
    // error if initValue type string
    try {
      store.dispatch(1123);
    } catch (e) {
      console.log(e);
    }
  • context run

    import { storeFactory, RunContext } from '@jashkasoft/rx-jstore';   
    
    const store = storeFactory<number>();
    const sub = store.subscribe((n: number) => {
      console.log('number', n);
    });
    
    function youContext(fn: Function) {
     fn();
    }
    
    store.changeContext((fn: RunContext) => youContext(fn));
    store.dispatch(100000000);
    store.destroy(sub);
  • selector

    import { JStore } from '@jashkasoft/rx-jstore';   
    
    interface Obj {
        name: string;
        id: number;
        extra: {
          min: number;
          max: number;
        };
    }
    
    const store = new JStore<Obj>();
    
    const subscription = store.subscribe((value: Obj) => {
      console.log('store', value);
    });
    
    store.dispatch({
      name: 'name',
      id: 2,
      extra: {
        min: 1,
        max: 10
      }
    });
    store.dispatch({
      name: 'name',
      id: 2,
      extra: {
        min: 50,
        max: 100
      }
    });
    
    // selector, maybe reuse in other stores
    function minValueSelector(value: Obj): number {
      return value.extra.min;
    }
    
    store.select<number>(minValueSelector).subscribe(value => {
      console.log('selector min value', value);
    });
    
    store.destroy(subscription);

JStoreDispatcher over JStore

import { of, Observable } from 'rxjs';

import {
  ToNumberFormatter,
  ToStringFormatter,
  JStore,
  JStoreDispatcher,
  Middleware,
  MiddlewareData
} from '@jashkasoft@rx-jstore';

const storeNumber = new JStore<number>({
  storage: new LocalStorage<number>('number'),
  inputFormatters: [
    new ToStringFormatter()
  ],
  outputFormatters: [
    new ToNumberFormatter()
  ]
});
const subscriptionNumber = storeNumber.subscribe((value: number) => {
  console.log('storeNumber', value);
});


storeNumber.dispatch(1);


// destroy subscription (subscriptionNumber) and observable call complete
// storeNumber.destroy(subscriptionNumber);
// throw error if completed
/*try {
  storeNumber.dispatch(2);
} catch (e) {
  console.log(e);
}*/
  • Actions
    const dispatcher = new JStoreDispatcher(storeNumber);
    const actionInc = JStoreDispatcher.makeAction<number>(
      'inc',
      (state: number, payload: number) => {
        return of(state + payload);
      }
    );
    const actionDec = JStoreDispatcher.makeAction<number>('dec', (state: number, payload: number) => state - payload);
    
    // listener on action by action function
    const listener = dispatcher.on(actionInc, (value: number) => {
      console.log('on action {actionInc}: ', value);
    });
    
    dispatcher.action(actionInc, 1);
    
    // destroy listener
    listener();
    
    dispatcher.action(actionInc, 1); // 3
    
    dispatcher.destroy(subscriptionNumber);
  • Lock & unlock
    // lock dispatcher, another actions disable, throw error
    console.log('lock dispatcher1');
    dispatcher.lock();
    try {
      // error
      dispatcher.action(actionInc, 1);
    } catch (e) {
      console.log(e);
    }
    // unlock, try to unlock two or more - error
    dispatcher.unlock();
    
    dispatcher.action(actionInc, 1);
  • Snapshots
    // snapshot with history & store, date, name
    const snapshot1 = dispatcher.makeSnapshot('three');
    
    dispatcher.action(actionDec, 1);
    
    console.log('restore....');
    // restore snapshot with history, value
    dispatcher.restoreSnapshot(snapshot1);
    
    dispatcher.action(actionDec, 1);
  • Middleware
    const dispatcher = new JStoreDispatcher(storeNumber);
    class AddMiddleware implements Middleware {
      public next<T>(data: MiddlewareData<T>): Observable<number> {
        const n = Math.floor(Math.random() * 10); // or http request
        /*if (n % 2 === 0) {
          throw new Error('n % 2 === 0');
        }*/
        return of(n);
      }
    }
    // named action with state, saved in history
    // action as function
    const actionInc = JStoreDispatcher.makeAction<number>(
      'inc',
      (state: number, payload: number, middlewareData: any) => {
        console.log('random number', middlewareData);
        return of(state + payload);
      },
      new AddMiddleware()
    );
    const actionDec = JStoreDispatcher.makeAction<number>('dec', (state: number, payload: number) => state - payload);
    
    // listener on action by action function
    const listener = dispatcher.on(actionInc, (value: number) => {
      console.log('on action {actionInc}: ', value);
    });
    
    // destroy listener
    listener();

For development

Переходим в директорию с проектом
cd folder-name
Установка зависимостей
yarn
Запуск сборки приложения и веб-сервера:
yarn run serve
Сборка приложения с минификацией:
yarn run build