Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

reactive-function

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

reactive-function - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

21

index.js

@@ -18,14 +18,13 @@ var ReactiveProperty = require("reactive-property");

// A map for properties based on their assigned id.
// Keys are property ids, values are reactive properties.
var propertiesById = {};
var properties = {};
// Assigns ids to properties for use as nodes in the graph.
var assignId = (function(){
var idCounter = 1;
var counter = 1;
return function (property){
if(!property.id){
property.id = idCounter++;
propertiesById[property.id] = property;
property.id = counter++;
properties[property.id] = property;
}

@@ -50,2 +49,3 @@ };

// Get the values for each of the input reactive properties.
var values = inputs.map(function (input){

@@ -55,3 +55,6 @@ return input();

// If all input values are defined,
if(defined(values)){
// invoke the callback and assign the output value.
output(callback.apply(null, values));

@@ -94,2 +97,5 @@ }

// Remove the reference to the 'evaluate' function.
delete output.evaluate;
};

@@ -106,3 +112,3 @@

.map(function (id){
return propertiesById[id];
return properties[id];
})

@@ -122,3 +128,4 @@ .forEach(function (property){

// Multiple sequential executions of the returned function within the same tick of
// the event loop will collapse into a single invocation of the original function.
// the event loop will collapse into a single invocation of the original function
// on the next tick.
// Similar to http://underscorejs.org/#debounce

@@ -125,0 +132,0 @@ function debounce(fn){

{
"name": "reactive-function",
"version": "0.3.0",
"version": "0.4.0",
"description": "A library for managing data flows and changing state.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -22,3 +22,3 @@ # reactive-function

Let's say you have two reactive properties to represent someone's name.
Suppose you have two reactive properties to represent someone's first and last name.

@@ -30,159 +30,43 @@ ```javascript

You can define a reactive function that depends on those two properties like this.
Suppose you'd like to have another property that represents the full name of the person.
```javascript
var fullName = ReactiveFunction(function (first, last){
return first + " " + last;
}, firstName, lastName);
var fullName = ReactiveProperty();
```
This defines a "reactive function" that will be invoked when its dependencies (`firstName` and `lastName`) are both defined and whenever either one changes. The function will be invoked on the next tick of the JavaScript event loop after it is defined and after any dependencies change.
You could set the full name value like this.
To force a synchronous evaluation of all reactive functions whose dependencies have updated, you can call:
```javascript
ReactiveFunction.digest();
fullName(firstName() + " " + lastName());
```
Now you can access the computed value of the reactive function by invoking it.
However, this sets the value of `fullName` only once, and it does not get updated when `firstName` or `lastName` change.
```javascript
console.log(fullName()); // Prints "Jane Smith"
```
Here's how you can define a reactive function that updates the full name whenever the first name or last name changes.
Here's some sample code from the tests that demonstrates the features of this library.
```javascript
it("Should depend on any number of reactive properties.", function () {
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
var c = ReactiveProperty(15);
var d = ReactiveFunction(function (a){
return a * 2;
}, a);
var e = ReactiveFunction(function (a, b, c){
return a + b + c;
}, a, b, c);
ReactiveFunction.digest();
assert.equal(d(), 10);
assert.equal(e(), 30);
ReactiveFunction({
inputs: [firstName, lastName],
output: lastName,
callback: function (first, last){
return first + " " last;
}
});
it("Should depend on a reactive function.", function () {
var a = ReactiveProperty(5);
var b = ReactiveFunction(function (a){
return a * 2;
}, a);
var c = ReactiveFunction(function (b){
return b / 2;
}, b);
ReactiveFunction.digest();
assert.equal(c(), 5);
});
it("Should depend on a reactive property and a reactive function.", function () {
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
var c = ReactiveFunction(function (a){
return a * 2;
}, a);
var d = ReactiveFunction(function (b, c){
return b + c;
}, b, c);
ReactiveFunction.digest();
assert.equal(d(), 20);
});
it("Should handle tricky case.", function () {
// a
// / \
// b |
// | d
// c |
// \ /
// e
var a = ReactiveProperty(5);
var b = ReactiveFunction(function (a){ return a * 2; }, a);
var c = ReactiveFunction(function (b){ return b + 5; }, b);
var d = ReactiveFunction(function (a){ return a * 3; }, a);
var e = ReactiveFunction(function (c, d){ return c + d; }, c, d);
ReactiveFunction.digest();
assert.equal(e(), ((a() * 2) + 5) + (a() * 3));
});
it("Should throw an error if attempting to set the value directly.", function () {
var a = ReactiveProperty(5);
var b = ReactiveFunction(function (a){
return a * 2;
}, a);
assert.throws(function (){
b(5);
});
});
it("Should clear changed nodes on digest.", function () {
var numInvocations = 0;
var a = ReactiveProperty(5);
var b = ReactiveFunction(function (a){
numInvocations++;
return a * 2;
}, a);
ReactiveFunction.digest();
ReactiveFunction.digest();
assert.equal(numInvocations, 1);
});
it("Should automatically digest on next tick.", function (done) {
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
var c = ReactiveFunction(function (a, b){
return a + b;
}, a, b);
setTimeout(function (){
assert.equal(c(), 15);
done();
}, 0);
});
```
# Case Study: Width and Height
This defines a "reactive function" that will be invoked when its inputs (`firstName` and `lastName`) are both defined and whenever either one changes. The function will be invoked on the next tick of the JavaScript event loop after it is defined and after any dependencies change.
Suppose you have some reactive properties that change, such as `width` and `height`.
To force a synchronous evaluation of all reactive functions whose dependencies have updated, you can call
```javascript
var my = {
width: ReactiveProperty(),
height: ReactiveProperty()
};
ReactiveFunction.digest();
```
Suppose also that you have a function that resizes an SVG element that depends on those two properties.
Now you can access the computed value of the reactive function by invoking it as a getter.
```javascript
var svg = d3.select("body").append("svg");
function render(){
svg
.attr("width", my.width())
.attr("height", my.height());
}
console.log(fullName()); // Prints "Jane Smith"
```
How can you invoke the `render function` when `my.width` and `my.height` change?
For more detailed example code, have a look at the [tests](https://github.com/curran/reactive-function/blob/master/test.js).

@@ -192,1 +76,5 @@ Related work:

* [ReactiveJS](https://github.com/mattbaker/Reactive.js)
* [EmberJS Computed Properties](https://guides.emberjs.com/v2.0.0/object-model/computed-properties/)
* [AngularJS Digest](https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest)
* [ZJONSSON/clues](https://github.com/ZJONSSON/clues)
* [Model.js](https://github.com/curran/model)

@@ -292,2 +292,66 @@ // Unit tests for reactive-function.

});
it("Should be able to implement unidirectional data binding.", function (){
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
ReactiveFunction({
inputs: [a],
output: b,
callback: function (a){
return a;
}
});
ReactiveFunction.digest();
assert.equal(b(), 5);
});
it("Should be able to implement bidirectional data binding.", function (){
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
function identity(x){ return x; }
ReactiveFunction({ inputs: [a], output: b, callback: identity });
ReactiveFunction({ inputs: [b], output: a, callback: identity });
ReactiveFunction.digest();
// The most recently added edge takes precedence.
assert.equal(b(), 10);
a(50);
ReactiveFunction.digest();
assert.equal(b(), 50);
b(100);
ReactiveFunction.digest();
assert.equal(a(), 100);
});
it("Should remove the 'evaluate' function from the output on destroy.", function (){
var a = ReactiveProperty(5);
var b = ReactiveProperty(10);
var c = ReactiveProperty();
var rf = ReactiveFunction({
inputs: [a, b],
output: c,
callback: function (a, b){
return a + b;
}
});
assert.equal(typeof c.evaluate, "function");
rf.destroy();
assert.equal(typeof c.evaluate, "undefined");
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc