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 🙏

© 2026 – Pkg Stats / Ryan Hefner

observable-state

v0.3.4

Published

Observables for creating reactive functional state in applications

Downloads

17

Readme

observable-state

Observables for creating reactive functional state in applications

Concept

There is a storm of new practices in application development, especially handling the state of your application. Flux is one approach that has spread like wildfire. It uses a concept of stores and a dispatcher. OM cursors is a different approach. You have a single state tree where you can point to values and listen for updates. These approaches have their benefits and challenges.

observable-state has more in common with OM cursors than FLUX in regards of storing state, but opens up for a functional and reactive way to update and grab the state. This might not make any sense to you, it did not to me before I started this project, so please read this article explaining why you would consider using functional reactive programming.

The API observable-state exposes is very accessible. You have other libraries like Rx, Bacon.js etc., but these are not very accessible in the sense of handling your application state.

API

Observable

You can observe any primitive and object, except when passing a function.

var value = Observable('foo');
get
var value = Observable('foo');
value.get(); // "foo"
set

Setting new values are async, but the propagation of updating observers is synchronous. This keeps updates predictable. So each set will start on the next tick of the event loop, but the work they do will be done within the same tick.

var value = Observable('foo');
value.set('bar');
value.get(); // "foo"
// Next tick
value.get(); // "bar"

You can also set an observable as a value. This effectively links observables.

var valueA = Observable('foo');
var valueB = Observable(valueA);
valueB.get(); // "foo"
valueA.set('bar');
// Next tick
valueB.get(); // "bar"
setSync

You can override the default async behavior of set, but it may have performance impact in larger applications.

var value = Observable('foo');
value.set('bar');
value.get(); // "bar"
onChange

Listen to changes on an observable. The value returned is a function that unsubscribes from getting the changes.

var value = Observable('foo');
var unsubscribe = value.onChange(function (value) {
  value; // "bar"
  usubscribe(); // This function will not run on changes any more
});
value.set('bar');
catch

If any observable or observables it depends on other causes an error it can be catched by this method.

var array = Observable(['foo', 'bar']);

// More on map soon
var reversed = array.map(function (value) {
  return value.reverse();
});
reversed.onError(function (error) {
  error; // TypeError: Undefined is not a function
});
array.set('foo');
map

Observe a value and based on that return a new value.

var someValue = Observable('foo');
var splitValue = someValue.map(function (value) {
  return value.split('');
});
splitValue.get(); // ['f', 'o', 'o']
splitValue.onChange(function (value) {
  value; // ['b', 'a', 'r']
});
someValue.set('bar');
reduce

Accumulate existing value with new changes.

var count = Observable(3);
var accCount = count.reduce(function (current, newCount) {
  return current + newCount;
});
accCount.get(); // 3
accCount.onChange(function (value) {
  value; // 9
});
count.set(6);
filter

Block changes that do not match filter.

var observable = Observable('foo');
var valuesContainingFObservable = observable.filter(function (value) {
  return value.indexOf('f') >= 0;
}); 
valuesContainingFObservable.get(); // "foo"
valuesContainingFObservable.onChange(function (value) {
  value; // Runs once, logging "foobar"
});
observable.set('bar');
observable.set('foobar');
debounce

Passes latest change within set interval.

var observable = Observable('foo');
var debouncedObservable = observable.debounce(200);
debouncedObservable.get(); // "foo"
debouncedObservable.onChange(function (value) {
  value; // "bar3"
});
observable.set('bar');
setTimeout(function () {
  observable.set('bar2');
  setTimeout(function () {
    observable.set('bar3');
  }, 50);
}, 100);
key

Lets you easily convert a value to a key/value pair.

var observable = Observable('bar');
var observableState = observable.key('foo');
observableState.get(); // { foo: 'bar' }
observableState.onChange(function (value) {
  value; // "foobar"
});
observable.set('foobar');
promise

Lets you define a function that returns a promise. The fullfilment of the promise will either trigger a change or be passed to a catch handler on rejection.

var observable = Observable();
var getUserObservable = observable.promise(function (value) {
  return ajaxPromise.get('/users/' ´value);
});
getUserObservable.onChange(function (value) {
  value; // {id: 123, name: 'John Doe'}
});
observable.set(123);

Observable.merge

Lets you merge observables into one new observable. The first observable passed will be the initial value of the new observable

var observableA = Observable('foo');
var observableB = Observable('bar');
var mergedObservable = Observable.merge(observableA, observableB);
mergedObservable.get(); // "foo"
mergedObservable.onChange(function (value) {
  value; // "foobar"
});
observableB.set('foobar');

You can also merge by using a map:

var observableA = Observable('foo');
var observableB = Observable('bar');
var mergedObservable = Observable.merge({
  c: observableA,
  d: observableB
});
mergedObservable.get().c; // "foo"
mergedObservable.onChange(function (value) {
  value; // {c: 'foo', d: 'foobar'}
});
observableB.set('foobar');

Observable.mergeValues

Lets you merge observables where the value is an object to one observable where the objects have been merged:

var observableA = Observable({
  foo: 'bar'
});
var observableB = Observable({
  foo2: 'bar2'
});
var mergedObservable = Observable.mergeValues(observableA, observableB);
mergedObservable.get().foo; // "bar"
mergedObservable.onChange(function (value) {
  value; // {foo: 'bar', foo2: 'foobar'}
});
observableB.set('foobar');