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

derivable

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

derivable

Functional Reactive State for JavaScript & TypeScript

  • 1.0.0-beta9
  • beta9
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
150
decreased by-35.06%
Maintainers
1
Weekly downloads
 
Created
Source

DerivableJS

State made simple → Effects made easy

npm Build Status Coverage Status Join the chat at https://gitter.im/ds300/derivablejs Empowered by Futurice's open source sponsorship program .min.gz size

Derivables are an Observable-like state container with superpowers. Think MobX distilled to a potent essence, served with two heaped spoonfuls of extra performance, a garnish of side effects innovation, and a healthy side-salad of immutability.

Quick start

There are two types of Derivable:

  • Atoms

    Atoms are simple mutable references to immutable values. They represent the ground truth from which all else is derived.

    import {atom} from 'derivable';
    
    const $Name = atom('Richard');
    
    $Name.get(); // => 'Richard'
    
    $Name.set('William');
    
    $Name.get(); // => 'William'
    

    N.B. The dollar-sign prefix is just a convention I personally use to create a syntactic distinction between ordinary values and derivable values.

  • Derivations

    Derivations represent pure (as in 'pure function') transformation of values held in atoms. You can create them with the .derive method, which is a bit like the .map method of Arrays and Observables.

    const cyber = word => word.toUpperCase().split('').join(' ');
    
    const $cyberName = $Name.derive(cyber);
    
    $cyberName.get(); // 'W I L L I A M'
    
    $Name.set('Sarah');
    
    $cyberName.get(); // 'S A R A H'
    

    Derivations cannot be modified directly with .set, but change in accordance with their dependencies, of which there may be many. Here is an example with two dependencies which uses the fundamental derivation constructor function:

    import {derivation} from 'derivable';
    
    const $Transformer = atom(cyber);
    
    const $transformedName = derivation(() =>
      $Transformer.get()($Name.get())
    );
    
    $transformedName.get(); // => 'S A R A H'
    
    const reverse = string => string.split('').reverse().join('');
    
    $Transformer.set(reverse);
    
    $transformedName.get(); // => 'haraS'
    
    $Name.set('Fabian');
    
    $transformedName.get(); // => 'naibaF'
    

    derivation takes a function of zero arguments which should dereference one or more Derivables to compute the new derived value. DerivableJS then sneakily monitors who is dereferencing who to infer the parent-child relationships.

Reactors

Declarative state management is nice in and of itself, but the real benefits come from how it enables us to more effectively manage side effects. DerivableJS has a really nice story on this front: changes in atoms or derivations can be monitored by things called Reactors, which do not themselves have any kind of 'current value', but are more like independent agents which exist solely for executing side effects.

Let's have a look at a tiny example app which greets the user:

import {atom, derivation, transact} from 'derivable'

// global application state
const $Name = atom("World");     // the name of the user  
const $CountryCode = atom("en"); // for i18n

// static constants don't need to be wrapped
const greetings = {
  en: "Hello",
  de: "Hallo",
  es: "Hola",
  cn: "您好",
  fr: "Bonjour",
};

// derive a greeting message based on the user's name and country.
const $greeting = $CountryCode.derive(cc => greetings[cc]);
const $message = derivation(() =>
  `${$greeting.get()}, ${$name.get()}!`
);

// set up a Reactor to print the message every time it changes, as long as
// we know how to greet people in the current country.
$message.react(
  msg => console.log(msg),
  {when: $greeting}
);
// $> Hello, World!

$CountryCode.set("de");
// $> Hallo, World!
$Name.set("Dagmar");
// $> Hallo, Dagmar!

// we can avoid unwanted intermediate reactions by using transactions
transact(() => {
  $CountryCode.set("fr");
  $Name.set("Étienne");
});
// $> Bonjour, Étienne!

// if we set the country code to a country whose greeting we don't know,
// $greeting becomes undefined, so the $message reactor won't run
// In fact, the value of $message won't even be recomputed.
$CountryCode.set('dk');
// ... crickets chirping

The structure of this example can be depicted as the following DAG:

Usage

DerivableJS is becoming fairly mature, and has been used for serious stuff in production with very few issues. I think it is safe to consider it beta quality at this point.

If your app is non-trivial, use Immutable.

With React

react-derivable is where it's at.

With Redux

DerivableJS can be used as a kind-of replacement for reselect, by just doing something like this:

const $Store = atom(null);

myReduxStore.subscribe(() => $Store.set(myReduxStore.getState()));

and then you derive all your derived state from $Store, rather than

Debugging

Due to inversion of control, the stack traces you get when your derivations throw errors can be totally unhelpful. There is a nice way to solve this problem for dev time. See setDebugMode for more info.

Examples (very wip)

The best example of writing good code with Derivables right now is the talk demo, which is presented as a 'diff tutorial' and should be read from the initial commit.

The next best is the routing walkthrough

I've also implemented a solution to @staltz's flux challenge.

There is a proper gitbook tutorial on the way!

Browser

Either with browserify/webpack/common-js-bundler-du-jour or build as umd bundle with npm run build -- --umd

Equality Woes

JavaScript is entirely whack when it comes to equality. People do crazy jazz trying to figure out if some stuff is the same as some other stuff.

If the data you're threading through DerivableJS needs its own notion of equality, make sure it has a sensible .equals method and everything will be fine.

If you're using a data library with some custom non-standard mechanism for doing equality checks (e.g. mori), then you'll need to re-initialize DerivableJS with a custom equality function.

import { withEquality } from 'derivable'

const { atom, derive, ..._} = withEquality(myCustomEqualityChecker);

Contributing

I heartily welcome questions, feature requests, bug reports, and general suggestions/criticism on the github issue tracker. I also welcome bugfixes via pull request (please read CONTRIBUTING.md before sumbmitting).

Inspiration <3

License

Copyright 2015 David Sheldrick <djsheldrick@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Keywords

FAQs

Package last updated on 10 Jul 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