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

kex

v2.1.5

Published

Kex is a tiny library for state managenent in JavaScript projects

Downloads

38

Readme

Kex

Kex is a tiny library for state managenent in JavaScript/TypeScript projects.

  • Small and fast
  • Zero dependencies
  • Async actions, cache, chainable actions out of box
  • Written on Typescript

Installation is simple and plain

  npm i kex

Principles

Just like Redux, Kex has reducers, actions and application state. But this time it's much simplier, because it not rescrict reducers to be pure functions (but they might be if you will).

Actions

Actions is objects that contain type and payload field:

{
  type: string;
  payload?: any;
}

You can dispatch action using dispatch method:

import { createStore } from 'kex';

const store = createStore();
const dispatcher = store.dispatch(action);

// will print current state after action finishes
dispatcher.then(state => console.log); 

Reducers

Reducers appears to be iterators which can return modifiers or promises which should be resolved into modifiers indeed. Modifiers is objects containing information how you want to change the state.

Let's say we have the state:

const state = {
  token: null,
  credentials: {
    login: '[email protected]',
    password: '********'
  }
}

and we want to change login field to something else:

import { applyModifiers } from 'kex'; // apply modifiers to specific object

const changeLoginModifier = {
  credentials: {
    login: '[email protected]'
  }
}

// this will change state to:
// const state = {
//   token: null,
//   credentials: {
//     login: '[email protected]',
//     password: '********'
//   }
// }
applyModifiers(state, changeLoginModifier);

As you can see, modifiers may contain only changes we want to apply to our state rather than whole state. applyModifiers works recursively and merge change of any level right into your state.

A typical reducer may look like this:

const function* reducer(action: KxAction) {
  switch (action.type) {
    ...
    case 'action_name':
      yield { some: 'changes' };
      break;
    ...
    case 'another_action_name':
      // async reducers out of box
      yield Promise.resolve({ more: 'changes' });
      break;
    ...
  }
}

Also Kex allows you to create chainable actions. This means that your reducer may dispatch actions on its own. To do that you should use actions field on the top of your state:

const function* reducerWithChainableAction(action: KxAction) {
  switch (action.type) {
    ...
    case 'chainable_action':
      const { actions } = store.getState()

      yield {
        some: 'changes',
        actions: [
          // if other reducers added thier actions in queue
          ...actions, 
          // after current action perform specified actions
          { type: 'action_name' },
          { type: 'another_action_name', payload: your_payload }
        ]
      };
      break;
    ...
  }
}

actions field creates and clears automatically, all you need to do is add some actions in case you need it.

To set reducers use replaceReducers method:

import { createStore } from 'kex';

const store = createStore();

store.replaceReducers(...reducers);

Reducers order in array actually matters because resolving process in linear. It means that reducers change the state one by one even if they async.

State

You can import storage at any point of your application. Use method getState to get current state:

import { createStore } from 'kex';

const store = createStore();

store.getState();

To modify your state without actions you may use update method:

import { createStore } from 'kex';

const store = createStore();

store.update(modifier);

You can subscribe to state changes using addStorageListener (and cancel the subscription using removeStorageListener method):

import { createStore } from 'kex';

const store = createStore();

const listener = (state, change) => {
  console.log(change.action === null ? 'Changed manually' : `By ${change.action} action`);
  console.log(`Changes: `, change.changes);
};

store.addStorageListener(listener);
store.removeStorageListener(listener);

You also can get history of state change using history() method:

import { store } from 'kex';

store.setHistoryMaxSize(10); // 10 is default value
store.history(); // will return 10 last actions

To clear your state use clear method:

import { store } from 'kex';

store.clear();

update and clear methods will appear in history, but action field will be set to null.

Example

  import { createStore, KxAction } from 'kex';

  const store = createStore();

  store.update({
    counter: 0,
    thisWillNotBeChanged: null
  })

  const function* counterReducer(action: KxAction) {
    const { counter } = kxStore.getState();
    
    switch (action.type) {
      case 'INCREMENT':
        yield {
          counter: counter + 1;
        };
        break;
      case 'ADD': 
        if (action.payload < counter) {
          return;
        }
      
        yield {
          actions: Array(action.payload - counter).fill({ type: 'INCREMENT' })
        }
    }
  }

  store.replaceReducers(counterReducer);

  // {
  //   counter: 10,
  //   thisWillNotBeChanged: null
  // }
  store.dispatch({ type: 'ADD', payload: 10 }).then(console.log);

Cache

Kex also support cache feature (key-value storage inside your state). You can change cache manually using dispatch and update methods but we strongly recommend to use setCache method insted. You can get your cache records using getCache method:

  import { createStore } from 'kex';

  const store = createStore();

  store.setCache('key', 'value'); // save key-value pair in cache (token === undefined)

  // You can use tokens to invalidate cache after token expires or changes
  store.setCache('foo', 'bar', 'token') // save key-value pair in cache (token === 'token')

  /*
   * After this state will look like this:
   *  {
   *    actions: [],
   *    cache: {
   *      key: {
   *        token: undefined,
   *        value: 'value'
   *      },
   *      foo: {
   *        token: 'token',
   *        value: 'bar'
   *      }
   *    }
   *  }
   * 
   */

  store.getCache('wrong_key') // null
  store.getCache('key'); // 'value'
  
  store.getCache('foo'); // null
  store.getCache('foo', 'token') // 'bar'
  store.getCache('foo', 'wrong_token') // null

  // You can change token and value any time
  store.setCache('foo', 'baz', 'token');
  store.getCache('foo', 'token'); // 'baz'

  store.setCache('foo', 'new_baz', 'new_token');
  store.getCache('foo', 'new_token'); // 'new_baz'

Contributing

If you want to contribute to project please contact me. I'm open to discuss the concept.