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

neodux

v0.0.6

Published

Neodux - State Management for JavaScript

Downloads

3

Readme

Neodux

Neodux is a state container for JavaScript.

Inspired by Redux, Neodux aims to be quite similar for those who are already using Redux, but proposes a (subjectively) simpler and easier to use API for those who are new to state management.

Motivation - Comparing Neodux/Redux

Similarities

Neodux borrows a lot of the same definitions from Redux (or flux general). Things like dispatching an action in Redux/flux is exactly what you would expect in Neodux.

In Redux, you have Reducers that change the state tree. In Neodux we have Action Handlers that change the state tree. Both takes in the current state and optionally a payload and returns a new state.

In the grand scheme of things, the two are identical. In fact, existing Redux users can build Action Handlers in almost the same way Reducers are built. There is even a utility function in the library called combineActionHandlers!

Differences

1. Subscribe to anything

Any data in the state tree can be subscribed to. This is achieved by adding an additional layer of observables on top of the state tree. The state object iself is a plain-old-javascript-object, but an observerables is what you interface with when you want to subscribe to data changes. This additional layer makes it possible for subscribers to only be called only when relevant data in the state tree has changed.

2. Async by default

Sometimes there are things happening in an app that is just async in nature. In Neodux, when an action handler returns a promise, the store waits for the data to be resolved before an update is considered complete.

This probably raises some questions:

What about API calls that are asynchronous but the result of the call needs to be added to state tree? Won't waiting for this call result in unwanted side effects?

For action handlers that do not directly affect what is on the state tree, you can register them as "sideEffects". A side effect is just an action handler where the return value is ignored by state tree. Side effects has full access to the data in the state tree and should dispatch additional actions if it needs to mutate it.

3. Less boilerplate code

We think that action handlers created in the preferred way will result in less boilerplate code when compared to equivalent action/reducer code in a Redux implementation.

More detail on this thought can be found in the documentation.

Neodux in Action

Below is an example of a simple stop watch app built with Neodux. The example below demonstrates the preferred way of doing state management with Neodux.

A Neodux and Redux implementation comparison can be found here: https://github.com/davinche/neodux-test

 import {actions} from './dist/index.es.js';
 /**
 * This is an action handler. Note that the section of the state tree
 * it will be changing is indicated by the "selector" property.
 *
 * For existing Redux users: notice the lack of "switching" on action.type.
 * Under the hood this is still happening, but when actions and reducers
 * are "1-to-1", this process has been abstracted away. 
 *
 * You can still define an "action.type" via the three argument version
 * of `actions.register`.
 */
actions.register('incrementSec', {
  selector: 'clock.sec',
  handler: async function({state, dispatch}) {
    // initial value
    if (state === undefined) {
      return 0
    }
    // increment seconds
    const next = (state + 1) % 60;
    // increment minute after rollover
    if (next === 0) {
      dispatch('incrementMin');
    }
    return next;
  }
});

actions.register('incrementMin', 'INCREMENT_MIN', {
  selector: 'clock.min',
  handler: function({state}) {
    // initial value
    if (state === undefined) {
      return 0;
    }
    // increment minute
    return state + 1;
  }
});

actions.register('resetClock', {
  selector: 'clock',
  handler: function() {
    return {
      min: 0,
      sec: 0
    }
  }
});

document.addEventListener('DOMContentLoaded', async function() {
  const store = await actions.createStore();
  const sec = document.getElementById('sec');
  const min = document.getElementById('min');
  const start = document.getElementById('start');
  const reset = document.getElementById('reset');

  // the subscribers is only notified when `clock.sec` changes
  store.get('clock.sec').subscribe(function(val) {
    sec.textContent = pad(val);
  });

  store.get('clock.min').subscribe(function(val) {
    min.textContent = pad(val);
  });

  let interval;
  // incrementSec and resetClock (as defined through the registration process above)
  // are functions you can pull off of `store.actions`.
  // Calling these functions is equivalent to calling
  // store.dispatch() with the proper action/type.
  // Optionally, passing an argument into these calls populates
  // the `payload` field of the action dispatched.
  //
  // `incrementMin` was created using the three argument variant of the
  // register method.
  // The `action.type` for incrementMin is "INCREMENT_MIN".
  //
  // If you were to call `store.action.incrementMin(1)`,
  // this would be equivalent to:
  //
  // `store.dispatch({type: 'INCREMENT_MIN', payload: 1});`
  const {incrementSec, resetClock} = store.actions;
  start.addEventListener('click', function(e) {
    e.preventDefault();
    e.stopPropagation();
    start.disabled = true;
    interval = setInterval(incrementSec, 1000);
  });

  reset.addEventListener('click', function(e) {
    e.preventDefault();
    e.stopPropagation();
    start.disabled = false;
    clearInterval(interval);
    resetClock();
  });
});

LICENSE

MIT