tigress v0.0.34
Tigress
Overview
tigress is a state management library that takes advantage of the robust type information available in TypeScript. It maintains a root state store which should be some immutable data structure and allows for atomically reading and writing that state store and receiving reactive change notifications upon state changes. It facilitates the creation of reusable components by providing a robust machanisms for navigating tree-like data structures.
tigress also provides constructs for reactive state computations along with React integration to allow for reactive view changes. In addition, there is advanced support for using state containers in data validation scenarios that allows for attaching validation metadata at any point in the state tree as well as accessing the current DB value of data being updated.
tigress's change notifications are compatible with RxJS and the proposed ECMAScript Observable specification.
Ref's
State containers in tigress are called Refs. Refs come in read-only and read-write variants. All readonly variants take a simple RO suffix (i.e. RefRO). All Refs take a single type parameter
representing the type of state managed by the Ref, ex: Ref<number>. When we refer to the types
of Ref's in TypeScript, the interface form (IRef or IRefRO) is usually used as the return
value for functions in TypeScript.
rootRef
To create a new Ref use the rootRef function passing in the initial state:
const myRef : IRef<number> = rootRef(0);get
The most basic operation for using Ref's is to get the current state using the get() method.
console.log(myRef.get());
// 0Dependency Tracking
Calling get in a reactive computation (either inside a reaction or reactive React component)
will automatically register the Ref as a dependency of the computation. This means that whenenver
the Ref updates the reactive computation will update. (To get the current state without
registering the Ref as a reactive dependency, use getNonReactive.)
Nullability
Because Refs are meant to work with tree-like data structures, given a type T that is
non-null we can't know whether it is the child of some nullable parent. So get always
returns T | null. (There is a variant of get called getResolved for "resolved" Ref's
that returns a non-null value but this is an advanced topic).
swap and reset
If we have a regular read-write Ref, swap and reset are used to modify the state. swap takes
an update function which takes the current state and returns the new state. reset simply takes a
value to set as the new state. Both swap and reset return the new value of the state after the
operation. Because Ref's could point to values in nested tree data structures,
swap and reset are not guaranteed to succeed and thus the return value is the only reliable
way to know what the actual value of the state is after attempting to mutate it.
Ex:
myRef.swap(cur => cur != null ? cur + 1 : cur);
console.log(myRef.get());
// 1
myRef.reset(3);
console.log(myRef.get());
// 3Nullability
Because of the complexities in working with tree-like data structures, the update function
passed to swap must take a nullable value and can return a nullable value regardless of what
the underlying type for the Ref is. reset will only take a type that corresponds to the
nullability of the underlying type. Both swap and reset may take a nullable value.
subscribe
The subscribe method is used to listen to change notifications from any Ref-like containers.
subscribe takes an IObserver parameter and returns an ISubscription value. IObserver
and ISubscription in tigress correspond almost exactly to the Observer and Subscription
interfaces specified in https://github.com/tc39/proposal-observable, with the minor difference
that tigress's IObserver allows all fields to be optional. This allows for listening to
changes simply by providing the next parameters of IObserver:
myRef.subscribe({next: x => console.log(x)});Prop's and Child Ref's
tigress allows for easy interaction with nested state trees via Props which are
typed representations of the properties of objcets. There
are two basic Prop interfaces: IProp and IPropRO and read-write and read-only
properties respectively. All Prop's have a getter method and a string name and
read-write Prop's also have a setter method.
Prop Basics
Anything conforming to the IProp or IPropRO can be used in Tigress. The
simplest way to create Prop's is to use the provider Prop and PropRO types.
Prop getters, setters and name's are described below.
getter
A Prop getter is a function taking a parent value and returning a child value. To deal cleanly with nested trees, getters must always accept a possibly null parent and can always return a nullable value regardless of the underlying nullability of this Prop.
setter
A Prop setter is a function taking a parent value and a new child value and return a new value for the parent. To deal cleanly with nested trees, setters must always accept a possibly null parent value and possibly null new child value and can always return a nullable value. Thus it is up to Prop implementations to properly handle or reject null values.
name
The Prop's name is more than just a description
string name, it is used to navigate metadata trees and
thus must be carefully chosen. This is an advanced topic
which will be discussed later in more detail.
Ref child and childRO
Prop's are used by Ref's in order to create "child" Ref's.
That is - Ref's that behave just like any other Ref, but point
to a child value in the state tree. Every IRef has child
function which takes an IProp and returns another read-write
IRef pointing to the child. Every IRef and IRefRO have
a childRO function which takes an IPropRO and returns
a read-only IRefRO pointing to the child.
Creating Prop's via code-generation
Prop's are not intended to be created by hand except in the most basic cases. Internally Anywhere generates Props for all of the types in its API backend using Template Haskell. A similar code generator code be created for Typescript types using the Typescript compiler API.
Reactions
TODO
Resolved Ref's
TODO
Metadata
TODO
Clean Copy Ref's
TODO
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago