Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Derivables are an Observable-like state container with superpowers. Think MobX distilled to a potent essence, served with two heaped tablespoons of extra performance, a garnish of declarative effects management, and a healthy side-salad of immutability.
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 simple convention I use to create a visual distinction between ordinary values and derivable values.
Derivations
Derivations are declarative transformations of values held in atoms. You can create them with the derive
function.
import {derive} from 'derivable';
const cyber = word => word.toUpperCase().split('').join(' ');
const $cyberName = derive(() =>
cyber($Name.get())
);
$cyberName.get(); // 'W I L L I A M'
$Name.set('Sarah');
$cyberName.get(); // 'S A R A H'
Unlike atoms, derivations cannot be modified in-place with a .set
method. Their values change only when one or more of the values that they depend upon change. Here is an example with two dependencies.
const $Transformer = atom(cyber);
const $transformedName = derive(() =>
$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'
derive
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.
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, derive, 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 = derive(() =>
greetings[$CountryCode.get()]
);
const $message = derive(() =>
`${$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:
Smaller API surface area.
There are far fewer kinds of thing in DerivableJS, and therefore fewer things to learn and fewer surprising exceptions and spooky corners. This reduces noise and enhances one's ability to grok the concepts and wield the tools on offer. It also shrinks the set of tools on offer, but maybe that's not a bad thing:
It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove.
- Antoie de Saint Exupéry
No transparent dereferencing and assignment.
It is always necessary to call .get
on derivables to find out what's inside, and you always have to call .set
on atoms to change what's inside.
This provides a consistent semantic and visual
distinction between ordinary values and derivable values.
No observable map and array types.
So you probably have to use something extra like Immutable or icepick to deal with collections. Not great if you're just out to get shit done fast, but the benefits of immutable collections become more and more valuable as projects mature and grow in scope.
More subtle control over reactors
DerivableJS has a tidy and flexible declarative system for defining when reactors should start and stop. This is rather nice to use for managing many kinds of side effects.
Speed
DerivableJS is finely tuned, and propagates change significantly faster than MobX. [link to benchmark-results.html forthcoming]
DerivableJS is fairly mature, and has been used enough in production by various people to be considered a solid beta-quality piece of kit.
The fantastic project react-derivable lets you use derivables in your render method, providing seamless interop with component-local state and props.
DerivableJS works spiffingly with Immmutable, which is practically required if your app deals with medium-to-large collections.
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.
Either with browserify/webpack/common-js-bundler-du-jour, or clone the repo, run npm install && npm run build
, then grab the UMD bundle from dist/derivable.umd[.min].js
(source maps are also available).
import { withEquality } from 'derivable'
const { atom, derive, ..._} = withEquality(myCustomEqualityChecker);
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).
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.
FAQs
Functional Reactive State for JavaScript & TypeScript
The npm package derivable receives a total of 109 weekly downloads. As such, derivable popularity was classified as not popular.
We found that derivable demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.