-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,310 @@ | ||
## API | ||
|
||
### Atom | ||
|
||
Atoms are simple mutable references to immutable values. They represent the | ||
ground truth from which all else is derived. | ||
|
||
#### atom(value: mixed): Atom | ||
|
||
#### .set(value: mixed): void | ||
|
||
#### .get(): mixed | ||
|
||
#### .update(mixed => mixed): void | ||
|
||
#### .proxy(descriptor): Proxy | ||
|
||
#### .derive(mixed => mixed): Derivation | ||
|
||
#### .maybeDerive(mixed => mixed): Derivation | ||
|
||
#### .orDefault(mixed | Atom | Derivation | Proxy): Derivation | ||
|
||
#### .react(mixed => void, opts: Lifecycle): void | ||
|
||
See [Reactions](#reactions). | ||
|
||
#### .maybeReact(mixed => void, opts: Lifecycle): void | ||
|
||
See [Reactions](#reactions). | ||
|
||
### Derivation | ||
|
||
Derivations are declarative transformations of values held in atoms. 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. | ||
|
||
#### derive(() => mixed): Derivation | ||
|
||
#### .derive(mixed => mixed): Derivation | ||
|
||
#### .maybeDerive(mixed => mixed): Derivation | ||
|
||
#### .orDefault(mixed | Atom | Derivation | Proxy): Derivation | ||
|
||
#### .react(mixed => void, opts: Lifecycle): void | ||
|
||
See [Reactions](#reactions). | ||
|
||
#### .maybeReact(mixed => void, opts: Lifecycle): void | ||
|
||
See [Reactions](#reactions). | ||
|
||
### Proxy | ||
|
||
``` | ||
type CompositeProxy<T> = { | ||
get(): T; | ||
set(value: T): void; | ||
}; | ||
proxy(descriptor: Proxy): CompositeProxy | ||
type Proxy<ParentType, ChildType> = { | ||
get(source: ParentType): ChildType; | ||
set(source: ParentType, value: ChildType): ParentType; | ||
}; | ||
``` | ||
|
||
#### proxy(descriptor): Proxy | ||
|
||
#### .set(value: mixed): void | ||
|
||
#### .get(): mixed | ||
|
||
#### .update(mixed => mixed): void | ||
|
||
#### .proxy(descriptor): Proxy | ||
|
||
#### .derive(mixed => mixed): Derivation | ||
|
||
#### .maybeDerive(mixed => mixed): Derivation | ||
|
||
#### .orDefault(mixed | Atom | Derivation | Proxy): Derivation | ||
|
||
#### .react(mixed => void, opts: Lifecycle): void | ||
|
||
See [Reactions](#reactions). | ||
|
||
#### .maybeReact(mixed => void, opts: Lifecycle): void | ||
|
||
See [Reactions](#reactions). | ||
|
||
### Reactions | ||
|
||
Reaction allows you to react on changes happend in any derivable item (atom, | ||
derivation or proxy). Reaction method accepts callback and lifecycle options | ||
|
||
#### Lifecycle | ||
|
||
**from: Derivable<boolean> | (Derivable => boolean)** | ||
|
||
Used to determine the start of the reactor's lifecycle. When it becomes truthy, | ||
the reactor is initialized. After which point this property is not used. | ||
|
||
**when: Derivable<boolean> | (Derivable => boolean)** | ||
|
||
Causes the reactor to be started and stopped based on the truthiness of the | ||
given condition. | ||
|
||
**until: Derivable<boolean> | (Derivable => boolean)** | ||
|
||
Used to determine the end of a reactor's lifecycle. When it becomes truthy the | ||
reactor is killed, after which point the reactor will never be used again and is | ||
eligible for garbage collection. | ||
|
||
**skipFirst: boolean** | ||
|
||
Causes the first invocation (and only the first invocation) of the reactor to be | ||
ingored. | ||
|
||
**once: boolean** | ||
|
||
Causes the reactor to be killed immediately following its first invocation (not | ||
counting the skipped invocation, if `skipFirst` is set to true). | ||
|
||
#### .react(mixed => void, opts: Lifecycle): void | ||
|
||
Accept callback with current derivable value and [Lifecycle](#lifecycle). | ||
|
||
#### .maybeReact(mixed => void, opts: Lifecycle): void | ||
|
||
Accept callback which is called with current derivable value if the value is not | ||
null or undefined and [Lifecycle](#lifecycle). | ||
|
||
### Transaction | ||
|
||
#### transact(() => void): void | ||
|
||
Executes passed function in the context of a transaction. | ||
|
||
In a transactional context, changes to atoms do not have side effects. All | ||
changes made during the transaction are propagated for side effects when the | ||
transaction commits. | ||
|
||
```js | ||
const firstName = `Joe`, | ||
lastName = `Schmoe`; | ||
|
||
derive`My name is ${firstName} ${lastName}`.react( | ||
x => console.log(x); | ||
); | ||
// $> My name is Joe Schmoe | ||
``` | ||
|
||
All good, but now we want to change the name to Tigran Hamasayan. | ||
|
||
```js | ||
firstName.set(`Tigran`); | ||
// $> My name is Tigran Schmoe | ||
``` | ||
|
||
Doh! Tigran Schmoe isn't a person! We certainly don't want reactors to think he | ||
is, that could be totally confusing for someone. | ||
|
||
`transact` to the rescue! Let's abort the previous mission and try changing the | ||
name to William Blake without ever having a William Schmoe. | ||
|
||
```js | ||
transact(() => { | ||
firstName.set(`William`); | ||
lastName.set(`Blake`); | ||
}); | ||
// $> My name is William Blake | ||
``` | ||
|
||
#### transaction((...args) => void): (...args) => void | ||
|
||
Wraps passed function such that its body is executed in a transaction. Preserves | ||
its input and output semantics. | ||
|
||
```js | ||
const firstName = `Joe`, | ||
lastName = `Schmoe`; | ||
|
||
derive`My name is ${firstName} ${lastName}`.react( | ||
x => console.log(x); | ||
); | ||
// $> My name is Joe Schmoe | ||
|
||
setTimeout(transaction(() => { | ||
firstName.set(`William`); | ||
lastName.set(`Blake`); | ||
}), 1000); | ||
|
||
// ... 1 second later ... | ||
// $> My name is William Blake | ||
``` | ||
|
||
#### atomically(() => void): void | ||
|
||
As `transact` but will not create a (nested) transaction if already in a | ||
transaction. | ||
|
||
#### atomic((...args) => void): (...args) => void | ||
|
||
As `transaction` but will not create a (nested) transaction if the returned | ||
function is invoked within a transaction. | ||
|
||
#### ticker(): t | ||
|
||
Creates a new ticker | ||
|
||
**t.tick(): void** | ||
|
||
Runs all pending reactions | ||
|
||
**t.release(): void** | ||
|
||
Releases this ticker, rendering it useless | ||
|
||
### Utils | ||
|
||
#### setDebugMode(debugMode: boolean): void | ||
|
||
Enable or disable debug mode. | ||
|
||
This causes Errors to be created (but not thrown) alongside derivations in order | ||
to capture the stack trace at their point of instantiation. In case a derivation | ||
throws an error itself when being computed, its instantiation stack trace is | ||
logged such that it becomes easy to determine exactly which derivation is | ||
throwing. Creating errors is quite slow, so you probably should not keep this | ||
enabled for production. | ||
|
||
#### isAtom(value: mixed): boolean | ||
|
||
Returns true if passed value is an Atom. | ||
|
||
#### isDerivation(value: mixed): boolean | ||
|
||
Returns true if passed value is a derivation, i.e. a derivable which is not an | ||
atom. | ||
|
||
#### isProxy(value: mixed): boolean | ||
|
||
Returns true if passed value is a proxy of atoms. | ||
|
||
#### isDerivable(value: mixed): boolean | ||
|
||
Returns true if passed value is any of atoms or derivations. | ||
|
||
#### struct(value: Object | Array): Derivable | ||
|
||
Given some plain JavaScript `Object` or `Array` (or some nested combination | ||
thereof) containing one or more derivable things, returns a new derivable | ||
representing the input collection with unpacked values. e.g. | ||
|
||
```js | ||
const a = atom(`Andrew`), | ||
b = atom(`Bernice`), | ||
c = atom(`Charlie`); | ||
|
||
const together = struct({ a: a, bandc: [b, c] }); | ||
|
||
together.react(names => { | ||
console.log(`A stands for ${names.a}`); | ||
console.log(`B stands for ${names.bandc[0]}`); | ||
console.log(`C stands for ${names.bandc[1]}`); | ||
}); | ||
// $> A stands for Andrew | ||
// $> B stands for Bernice | ||
// $> C stands for Charlie | ||
|
||
c.set(`Chris`); | ||
// $> A stands for Andrew | ||
// $> B stands for Bernice | ||
// $> C stands for Chris | ||
``` | ||
|
||
#### unpack(value: Derivable | mixed): mixed | ||
|
||
If passed value is derivable, returns value.get(), otherwise returns value. | ||
|
||
#### captureDereferences(() => void): Array | ||
|
||
<Derivable> | ||
|
||
Returns array of all changed derivables with reactions inside passed function. | ||
e.g. | ||
|
||
```js | ||
const captured = captureDereferences(() => { | ||
const a = atom(1); | ||
const b = atom(2); | ||
const sum = derive(() => a.get() + b.get()); | ||
|
||
sum.react(d => { | ||
console.log(d); | ||
}); | ||
|
||
a.react(d => { | ||
console.log(d); | ||
}); | ||
}); | ||
/* | ||
Atom(1) | ||
Derivation(3) | ||
and a few internal derivations | ||
*/ | ||
``` |