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

reactive-property

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

reactive-property

A small library for getter-setter functions that react to changes.

  • 0.7.0
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

reactive-property NPM Build Status

This tiny library abstracts the getter-setter pattern described in Towards Reusable Charts (by Mike Bostock, 2012) and adds the ability to react to changes in state.

Installation

Install the library by running this command.

npm install reactive-property

Require it in your code like this.

var ReactiveProperty = require("reactive-property");

If you're not using NPM, you can require the script in your HTML like this.

<script src="//curran.github.io/reactive-property/reactive-property-v0.6.0.js"></script>

Or, you can use the minified version (1.5K).

<script src="//curran.github.io/reactive-property/reactive-property-v0.6.0.min.js"></script>

Usage

Create your first property.

var a = ReactiveProperty();

Set its value.

a(5);

Get its value.

a();

Listen for changes.

a.on(function(value){
  console.log("The value of 'a' changed to " + value);
});

Cancel your subscription.

function listener(){
  console.log("'a' changed!");
}
a.on(listener);
a.off(listener);
a(5); // The listener is NOT called.

For convenenience, the listener function is returned from the call to on, so the following would also work.

var listener = a.on(function (){
  console.log("'a' changed!");
});
a.off(listener);
a(5); // The listener is NOT called.

Set up method chaining by using a context object.

var my = {
  x: ReactiveProperty(5),
  y: ReactiveProperty(10),
  z: ReactiveProperty(15)
};
my.x(50)
  .y(100)
  .z(150);

For more detailed example code, have a look at the tests..

Background

After many attempts at building "frameworks" for data visualization (ModelJS, Chiasm), I have learned that abstractions come at a cost. Much to my dismay, I found that when I wanted to apply Chiasm to a particular project, the abstractions had too much surface area and stood in the way of customization. I found myself starting again from raw D3 examples to get projects done, and noticed that as a project grows in complexity organically, the most common need is to listen for changes in state.

This library is my attempt to create a "micro-framework" that eliminates the getter-setter boilerplate code and provides the ability to listen for changes in state. It is intentionally minimal, and no other features are provided. This is to minimize the surface area of this library, and make it appealing for others to adopt as a utility. It is intended for use with D3-based projects, as it helps you generate APIs that follow the D3 convention of chainable getter-setters, but it can be used with other libraries too.

This library is "complete" and fully functional as-is. Aside from bugs or edge cases that come up, no new features will be added to this library. This library is designed to be the foundation of larger systems, and additional functionality should arise by composing this library with other code.

A Note on Immutability

This library is essentially a state container. You will experience totally predictable behavior if you set property values to immutable values. For example, if you want a property to represent a list of things, it may be tempting to do this:

var myList = ReactiveProperty(["a"]);
myList.on(function (value){ console.log("Updated"); });
myList().push("b"); // Listener does not get invoked.

However, in this case, the listener does not get invoked when you push the element onto the array. The same is true for objects.

var myObject = ReactiveProperty({ x: 5 });
myObject.on(function (value){ console.log("Updated"); });
myObject().y = 10; // Listener does not get invoked.

In order to trigger the listener, you must invoke the setter, like this:

var myList = ReactiveProperty(["a"]);
myList.on(function (value){ console.log("Updated"); });
myList(["a", "b"]); // Listener does get invoked.

However, let's say you want to use push, how could that work?

var myList = ReactiveProperty(["a"]);
myList.on(function (value){ console.log("Updated"); });
myList().push("b"); // Object mutated, listener not invoked.
myList(myList()); // Listener does get invoked.

In the case of objects:

var myObject = ReactiveProperty({ x: 5 });
myObject.on(function (value){ console.log("Updated"); });
myObject().y = 10; // Object mutated, listener not invoked.
myObject(myObject()); // This triggers the listener, but is ugly.

The above solution does work, but it's actually mutating the value, then passing it into the setter. This is not ideal. In situations like this, you're better off using immutable types such as those provided in Immutable.js for complex value types. Here's what that would look like for arrays (Lists):

var myList = ReactiveProperty(Immutable.List(["a"]););
myList.on(function (value){ console.log("Updated"); });
myList(myList().push("b")); // Sets the new value, invokes the listener.

Here's what using immutable types would look like for arrays (Maps):

var myMap = ReactiveProperty(Immutable.Map({ x: 5 }););
myMap.on(function (value){ console.log("Updated"); });
myMap(myMap().set("y", 10)); // Sets the new value, invokes the listener.

This is a good solution, and yields predictable behavior that is easy to reason about.

Contributing

  • If you think this project is cool, please give it a star!
  • If you end up using this in an example on bl.ocks.org, please let me know by creating a GitHub issue, we can link to your example in this README.
  • Feel free to open GitHub issues if you have any questions, comments or suggestions.

I hope you enjoy and benefit from this project!

Keywords

FAQs

Package last updated on 24 Feb 2016

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

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