npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

storeon-substore

v1.4.0

Published

Substore utility for [Storeon]

Downloads

16,960

Readme

storeon-substore

npm version Build Status Coverage Status

Utility for creating feature sub store for Storeon.

It size is 420 B (minified and gzipped) and uses Size Limit to control size.

Overview

The goal of this library is provide the easy way to create feature sub store, which allows to work on sub state (projection of parent state) within the storeon events handler and returns sub state on get method call.

During work with mid scale application you can notice that on multiple places you have to make the projection of state, eg:

/**
 * @param {Store<{feature: {counter: number}}>} store 
 */
export function featureCounterModule(store) {
    store.on('@init', () => ({
        feature: {
            counter: 0
        }
    }));
    store.on('featureIncrement', state => ({
        feature: {
            ...state.feature,
            counter: state.feature.counter + 1,  
        }   
    }));
    store.on('featureDecrement', state => ({
        feature: {
            ...state.feature,
            counter: state.feature.counter - 1,  
        }   
    }));
    store.on('featureSet', (state, count) => ({
        feature: {
            ...state.feature,
            counter: count  
        }   
    }));
}

To eliminate the duplication of state projection each time when you reduce your state you can use feature sub store:

/**
 * @param {Store<{feature: {counter: number}}>} store 
 */
export function featureCounterModule(store) {
    const featureStore = createSubstore(store, 'feature'); 
    featureStore.on('@init', () => ({
        counter: 0
    }));
    featureStore.on('featureIncrement', state => ({
        counter: state.counter + 1,  
    }));
    featureStore.on('featureDecrement', state => ({
        counter: state.counter - 1,  
    }));
    featureStore.on('featureSet', (state, count) => ({
        counter: count  
    }));

}

Or even use sub store of sub store:

/**
 * @param {Store<{feature: {counter: number}}>} store 
 */
export function featureCounterModule(store) {
    const featureStore = createSubstore(store, 'feature'); 
    const featureCounterStore = createSubstore(featureStore, 'counter'); 
    featureCounterStore.on('@init', () => 0);
    featureCounterStore.on('featureIncrement', state => state + 1);
    featureCounterStore.on('featureDecrement', state => state - 1);
    featureCounterStore.on('featureDecrement', (state, count) => count);
}

Three important remarks:

  • The state delivered to handler attached to sub store, can get the undefined value if the state of the feature is not yet set.

Install

npm i storeon-substore --save

Usage

import createStore from "storeon";
import { createSubstore } from "storeon-substore";

// create store 
const store = createStore([]);

// create sub store
const featureStore = createSubstore(store, 'feature');

// registering handler on substore
featureStore.on('toggleFeatureBooleanFlag', (state) => ({
    // please notice that sub state can be undefined
    flag: state ? !state.flag : true, 
}));

// which is equivalent to 
// store.on('toggleFeatureBooleanFlag', (state) => ({
//     feature: {
//         ...state.feature,
//        flag: state.feature ? !state.feature.flag : true, 
//    }   
// }));

// @changed event
featureStore.on('@changed', (state, diff) => {
    // here the state is a state of featureStore
    // and diff contains only properties which are changed on featureStore level 
});

// dispatching event on sub store works exactly in same way as on parent one 
featureStore.dispatch('toggleFeatureBooleanFlag');

// taking state
featureStore.get(); // returns { flag: true }

// which is equivalent to 
// featureStore.get().feature; // returns { flag: true }

Scoped events

This library allows also to scope the events. By default, substore is operates on same set of events like parent store. But there is possibility to narrow scope of all dispatched events only to substore handlers. This can be useful for storeon modules reuse. Look at the example:

import createStore from "storeon";
import { createSubstore } from "storeon-substore";
// lets create generic counter module
const counterModule = (store: StoreonStore<any>) => {
    store.on('inc', state => ({
        count: (state?.count || 0) + 1
    }));
    store.on('dec', state => ({
        count: (state?.count || 0) + 1
    }));
}
// create master store
const store = createStoreon<any>([]);

// create counterA substore
// please notice that we are using third argument
const counterAStore = createSubstore(store, 'counterA', true);
counterModule(counterAStore);

// create counterB substore
// please notice that we are using third argument
const counterBStore = createSubstore(store, 'counterB', true);
counterModule(counterBStore);

// now lets dispatch events first on counterAStore
counterAStore.dispatch('inc');
console.log(store.get()) // { counterA: { count: 1 } }

// then on counterBStore
counterBStore.dispatch('inc');
console.log(store.get()) // { counterA: { count: 1 }, counterB: { count: 1 } }

Api

  • createSubstore - is factory function which returns sub feature store. Params:
    • parent the parent store, can be a result of createStore or other sub store created by createSubstore
    • key the sub state property key in parent state
    • scopeEvents (optional) boolean flag which will enable the events scoping, so every event dispatched on the substore will be only scoped to this substore, so only handlers attached to this substore will handle the event