Skip to content

React State manager drop-in replacement for Microsoft/ReSub

Notifications You must be signed in to change notification settings

FDMediagroep/ReSubstitute

Repository files navigation

Node.js CI Coverage Status CodeQL Node.js Package Bundle-size minified+gzip NPM

ReSubstitute

React State manager drop-in replacement for Microsoft/ReSub

Usage

  1. npm i -D @fdmg/resubstitute

Creating Stores

A store extends the ReSubstitute class. It is a class in which you can store whatever values you want. Typically you'll implement setters and getters to set or get some value from the store. In the setter-function you'll end by calling this.trigger(). This will notify all subscribers to the change.

ThemeStore.ts

import { ReSubstitute } from '@fdmg/resubstitute';

export enum Theme {
    SYSTEM = 'system',
    DARK = 'dark',
    LIGHT = 'light',
}

class ThemeStore extends ReSubstitute {
    private _theme: Theme = Theme.SYSTEM;

    setTheme(theme: Theme) {
        this._theme = theme;
        this.trigger();
    }

    getTheme() {
        return this._theme;
    }
}

export default new ThemeStore();

Subscribe

const subscriptionId = ThemeStore.subscribe(() => {
    // Called whenever `this.trigger()` is called within ThemeStore.
});

// Unsubscribe from the ThemeStore
ThemeStore.unsubscribe(subscriptionId);

Trigger blocks

Sometimes you may want to do lot of consecutive updates but you don't necessarily need to notify all subscribers for each of those updates. Then you can use the static function ReSubstitute.pushTriggerBlock() to push a block onto the stack. As long as there is a block on the stack, triggers will not cause subscribers to be notified.

const resub = new ReSubstitute();
resub.subscribe(() => {
    console.log('triggered');
});

// Add global trigger block to the stack
ReSubstitute.pushTriggerBlock();
// Add global trigger block to the stack
ReSubstitute.pushTriggerBlock();
resub.trigger(); // Nothing happens

ReSubstitute.popTriggerBlock();
resub.trigger(); // Nothing happens

ReSubstitute.popTriggerBlock();
resub.trigger(); // console.log('triggered');

Bypass trigger blocks

const resub = new ReSubstitute();
const resubBypass = new ReSubstitute(0, true);

resub.subscribe(() => {
    console.log('triggered');
});
resubBypass.subscribe(() => {
    console.log('bypass triggered');
});

// Add global trigger block to the stack
ReSubstitute.pushTriggerBlock();
resub.trigger(); // nothing happens
resubBypass.trigger(); // console.log('bypass triggered');

Subscribe to specific keys

const resub = new ReSubstitute();
// Subscribe to global events
resub.subscribe(() => {
    console.log('triggered');
});
// Subscribe only to key
resub.subscribe(() => {
    console.log('only triggered by testKey');
}, 'testKey');

resub.trigger(); // console.log('triggered');
resub.trigger('testKey'); // console.log('only triggered by testKey');

// console.log('triggered');
// console.log('only triggered by testKey');
resub.trigger(['testKey', ReSubstitute.Key_All]);

Throttled events

const resubThrottled = new ReSubstitute(500);
resubThrottled.subscribe(() => {
    console.log('triggered');
});
resubThrottled.trigger(); // console.log('triggered'); after 500ms
resubThrottled.trigger(); // trigger already scheduled so 2nd trigger is ignored