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

kilto

v0.4.1

Published

A state management system with easy async and low boilerplate.

Downloads

9

Readme

Kilto

Kilto is a state management solution with a similar API to Redux but with a paradigm that saves you from the the boilerplate that can make Redux feel excessively beurucratic.

Kilto has 0 dependencies and is puny, around 1kb gzipped. It works on both Node.js and in browsers back to IE8. To use async actions, you'll need to polyfill ES6 Promise in older browsers.

With Kilto you usally keep all of your application state in a single "store". When you want to interact with your state you dispatch a pure function that returns a new state based on the old state, rather that mutating it. This makes it very easy to derive your UI purely from the state.

Kilto's design includes a built-in paradigm to make async actions just as easy to write as synchronous ones, while still using pure functions of state and remaining predictable.

Contents

API

The API is extremely simple to learn and teach in a matter of minutes.

import { createStore } from 'kilto';

const initialState = {
  greeting: 'Hello world!',
  counter: 0
};

const store = createStore(initialState);

console.log(store.getState() === initialState);
// true

Easy enough, now we have a store which contains state. It's pretty lame if the state never changes, so lets dispatch an update:

const up = (state, value = 1) => {
  return {
    ...state,
    counter: state.counter + value
  };
};

const down = (state, value = 1) => {
  return {
    ...state,
    counter: state.counter - value
  };
};

store.dispatch(up, 5);

console.log(store.getState());
// { 
//  greeting: 'Hello world!',
//  counter: 5
// }

We dispatch pure functions, called actions, which return a new state based on the old state. Unlike Redux, there is no reducer, no action creator, no action types. Just actions. This reduces boilerplate and enforces better separation of concerns.

Pure functions are functions which don't mutate any values, they return a new value based exclusively on the parameters. Every time you call a pure function with the same parameters, it will return the same thing every time. This makes state predictable.

Notice how when up is called, the value parameter is passed the 5 from the dispatch call. The first argument up receives is the previous state, then comes the rest of the arguments used to call dispatch.

Now lets get notified when our state changes:


const printCounter = (newState) => {
  console.log('Current counter:', newState.counter);
};

store.subscribe(printCounter);

store.dispatch(down);
// Current counter: 4

store.dispatch(down, 2);
// Current counter: 2

That's all you need to get started using Kilto, but what about the elephant in the pure functional room: async and side effects. What if our action is asynchronous, like saving data to the server? We can't just dispatch async functions, because they would introduce side effects and race conditions which would ruin the predictive nature of our state!

For this, Kilto provides an elegant solution out of the box to run asynchronous actions:


const fetchGreeting = [
  async (state, target) => {
    const response = await fetch(`http://totallyrealapi.com/get_greeting?target=${target}`);
    const data = await response.json();
    return data.greeting;
  },
  (state, greeting, target) => {
    return { 
      ...state,
      greeting: greeting
    };
  }
];

store.subscribe((state) => console.log('Current greeting: ', state.greeting));
store.dispatch(fetchGreeting, 'universe');
/* Request begins in async. */

store.dispatch(up);
/* Action runs and returns immediately */
// Current greeting: Hello world!
// Current counter: 3

/* After a delay: */
// Current greeting: Greetings universe!
// Current counter: 3

Kilto also lets us pass an array of functions into dispatch. Kilto will evaluate each one in order, and when a function returns, it's result is piped into the second argument of next function. But wait! The first function is async, so it returns a promise! Kilto sees that the return is a promise and subscribes for the result. When it's ready it pipes the value into the second argument of the next function. The first argument of each function is always the current state.

The last function in an action must be a synchronous (pure) function of state that returns the new state. This guarantees that every new state is a pure function of the previous state. Notice how when we dispatched up it incremented the counter to 3. Some time after that, the async action finishes it's fetch and the second function in the fetchGreeting action initiates a new state change with the new greeting. Notice how in the end neither update overwrote the other's changes.

For more on asynchronous actions, look here.

Installation

Install Kilto with

npm install --save kilto

The usual way to use Kilto is with the ES6 syntax and a bundler like webpack:

import { createStore, bindActions } from 'kilto'
// OR import just what you need (not needed in webpack 2, which does treeshaking by default)
import createStore from 'kilto/lib/createStore';

You can also include the umd build directly in the browser:

<script src="node_modules/kilto/umd/Kilto.min.js"></script>
<script>var store = Kilto.createStore(initialState)</script>

In Node.js, browserify, or webpack, you can use the require syntax.

const { createStore } = require('kilto');
// OR
const createStore = require('kilto/lib/createStore').default;

Philosophy

Kilto follows a similar philosophy as Redux. The whole state of your app should usually be in a single store, though there are times where it makes more sense to split the state up into multiple stores. The only way to change state is to dispatch a pure function that returns the next state. You can also dispatch an array of functions, and the last function will serve as the pure function that returns the next state. All updates should be done through dispatches, which then means that all subscribers will immediately be notified as soon as the state changes.

With Redux you need to 'pre-register' your actions with the store, that is, tell your store on creation how it should respond to every action type in the reducer. This leads to large reducers that have to be split and combined using combineReducer or some other means. This is not necessary in Kilto, so managing a large single state tree is usually quite easy.

Kilto works great with immutable data. seamless-immutable is a great choice to ensure immutability, since it works entirely with standard javascript Objects and Arrays. Other options include immutable.js and mori. Even if you don't use a library to enforce that your data can't change without you knowing it, you should never mutate state!! This includes things like state.x = y and state.z.push(a). Don't do it! Your subscribers won't know the state has changed.

When you do things right and don't mutate state, it makes your app predictable. The current state of your applciation can only change in calls to dispatch, and whenever that is called and state is changed, every subscriber knows right away. This allows for a whole bunch of optimizations like O(1) time to compare huge objects.