Neurologically Paralyzing Mouseovers
Miss any of our Open RFC calls?Watch the recordings here! »

revalue

1.1.2 • Public • Published

revalue (Reactive Value)

A simple and intuitive way of doing incremental and reactive programming

Idea

In incremental or reactive programming, when a piece of data changes, only the outputs that depend on that piece of data will be recomputed and updated.

Standard libraries for reactive programming are powerful, but are more conceptually involved.

The idea behind revalue is simple: we register some variables and functions that depend on other variables and/or functions.

For example,

// This creates a registry `logic`
var logic = revalue(function(r) {
    var
        revenue = r.var( 150 ), // Creates a variable `revenue` with a value 150
        cost    = r.var( 100 ), // Creates a variable `cost` with a value 100
        
        // Creates a function that depdends on `revenue` and `cost` and
        // will get recalculated every time `revenue` or `cost` changes
        profit  = r.fun(revenue, cost).is(function(revenue, cost) {
            return revenue - cost;
        })
    ;
    
    // We can create "hidden" functions that are not accessible for the
    // user, but will still update whenever their dependencies change,
    // for example, for DOM updates.
    r.fun(profit).is(function(profit) {
        console.log("Profit is", profit);
    });
 
    // By returning the properties, we ensure they will appear in registry `logic`.
    return {
        revenue : revenue,
        cost    : cost,
        profit  : profit
    };
});

This example registers variables revenue and cost, and a function profit, which is automatically calculated as revenue minus cost. Then, we register a hidden function, which will output profit whenever it changes.

Every function and variable has a value that we can get with

logic.profit.get(); // Returns 50

Or, set with

logic.revenue.set( 150 );

What makes it powerful

When we change a variable or a function, then the functions that depend on it will get automatically recalculated. In the example above,

logic.profit.get();        // Returns 50
logic.revenue.set( 350 );  // Setting the revenue to 350 instead of 150
logic.profit.get();        // Returns 250

This approach is similar to a spreadsheet-like functionality and can be especially useful for

  • Specifying behaviour more declaratively
  • Implementing reactive DOM and templating systems
  • Working with changing app or component state
  • Creating customization system for Custom Elements

How to (TL;DR)

You can see commented examples under /demo folder for extra practice. The following is just an overview of all available features.

Working with registries

We can create registry in 2 different ways:

  1. Preferred way, through a function call

    var r1 = revalue(function(r) {
        // Note: r === revalue. We use it in an argument as a shortcut.
        var
            a = r.var( 1 ), // Creates variable `a` with a value 1
            b = r.var( 2 ), // Creates variable `b` with a value 2
            // Creates a function `x` that will always have a value `a + b`
            x = r.fun( a, b ).is(function(a,b) {
                return a + b;
            })
        ;
        // The returned properties will appear in `r1` registry
        return {a:a, b:b, x:x}
    });
  2. Alternative way, through an object:

    var r2 = revalue({
        'a' : 1,
        'b' : 2,
        'x' : {
            dependencies: ['a','b'],
            is: function(a,b) {
                return a + b;
            }
        }
    });

We can also add some variables to an existing registry by using the registry as the first argument:

revalue(r1, function(r) {
    var c = r.var( 3 );
    return {c: c};
});
// Alternatively,
revalue(r2, {
    c: 3
});

Working with variables and functions:

  • Getting:

    r1.x.get(); // Returns 3 (because x = a + b = 1 + 2 = 3)
  • Setting:

    r1.a.set(220);
    r1.x.get(); // Returns 222 (because x = a + b = 220 + 2 = 222)
  • Changing dependencies:

    r1.x.of([r1.c, r1.b]);
    r1.x.get(); // Returns 5 (because x = c + b = 3 + 2 = 5)
  • Changing function description:

    r1.x.is(function(a,b) {
        return a * b;
    });
    r1.x.get(); // Returns 6 (because x = c * b = 3 * 2 = 6)

A function can depend on the previous values of its dependencies as well:

r1.x.is(function(a, b, pre_a, pre_b) {
    return a * b + pre_a * pre_b;
});
r1.b.set(10);
r1.x.get(); // Returns 36 (because x = a * b + pre_a * pre_b = 3 * 10 + 3 * 2 = 36)

Functions from one registry can just as easily depend on functions / variables from the other registries:

revalue(r2, function(r) {
    var y = r.fun(r1.x).is(function(x) {
        return x / 2;
    });
    return {y: y}
});
r2.y.get(); // Returns 18 (because y = x / 2 = 36 / 2 = 18)

We can easily register a function / variable outside of a registry:

revalue.fun(r2.y).is(function(y) {
    document.getElementById('test').textContent = y;
});

Install

The utility is tiny, just about 1.2K minified and gzipped (3K minified).

Browser

Add to your HTML page:

<script src="path/to/revalue.js"></script>

NodeJS

Include revalue as a NodeJS module:

var revalue = require('./path/to/revalue.js');

See API Reference

License

MIT License

Install

npm i revalue

DownloadsWeekly Downloads

1

Version

1.1.2

License

MIT

Last publish

Collaborators

  • avatar