![Vivisector Logo](https://github.com/MatthewZito/vivisector-js/raw/HEAD/docs/vx.png)
Vivisector | Compact observables
![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)
API and Documentation
Table of Contents
Introduction
Note: this README is a WIP
Vivisector is a compact TypeScript library for hassle-free reactive programming. Vivisector allows you to tether actions to specific types of mutation events, rendering your application's state event-bound.
Furthermore, Vivisector grants you the ability to declaratively mutate state. Every event is accompanied by a done
function which can be used to either commit the state change or reject it.
Here's what that looks like:
const { vivisect } = require('vivisector-js');
const state = vivisect({
firstName: '',
lastName: '',
email: ''
})
.addEventListener('set', ({ prevState, nextState, done }) => {
if (!isValidEmail(nextState.email)) {
emitErrorMessage();
done(false);
} else {
sendWelcomeEmail();
done(true);
}
...
});
Features
Vivisector...
- has zero dependencies
- is compact at 3kb gzipped
- has a simple, straight-forward API
- supports TypeScript and JavaScript
With it, you can...
- instantly link/unlink actions to a variable's state
- harness the power of reactive programming without the excess boilerplate
- declaratively cancel or commit state changes before they happen
Installation
Install via NPM
npm install vivisector-js
or
yarn add vivisector-js
Documentation
Before we begin, here's a few quick notes that are rather important:
-
Vivisected
objects are COPIED by value, not reference
-
don't mutate state in callbacks - doing this will result in undefined behavior; that's what the done
function is for
-
nested objects become their own proxies
For example, in the following code
const o = vivisect({ a: {} });
Object.assign(o.a, someObject);
o.a
will invoke events with a base state of {}
Quick Start
Import Vivisector's vivisect
utility:
const { vivisect } = require('vivisector');
Create a new Observable - in this example, an array - and register a handler to fire when any new elements are added. We'll keep it simple for now by using the alwaysCommit
option, which means any state changes associated with events of the given type will always be committed.
const logAdditions = ({ type, prevState, nextState }) => console.log(`${type} captured. ${prevState} ==> ${nextState}`);
const users = vivisect(['Alice', 'Bob']);
users.addEventListener('add', logAdditions, { alwaysCommit: true });
users.push('Charlie');
Arrays and Objects can be vivisected
in this manner:
const albums = vivisect(['Tago Mago', 'Monster Movie', 'Ege Bamyasi']);
console.log(albums.find(i => i === 'Tago Mago'));
Event handlers are added by calling addEventListener
. This function will exist on any vivisected
object:
users.addEventListener(eventType, eventHandler, { alwaysCommit: true });
addEventListener
can listen to the following events...
Event Types
add
A new element or property has been added to the array or object. Callbacks will receive a function, done
, and an object consisting of:
Property | Value |
---|
type | String 'add', denoting the event-type that was triggered |
prevState | the previous state |
nextState | the next state, after the event we are listening to |
Fires on: Additive array functions; adding new properties
Type (TypeScript only) VX_LISTENER_INTERNALS.ADD
Note: Batched operations are individual events e.g. arr.push(1,2,3)
is three 'add' events
set
An existing element or property has changed. Callbacks will receive a function, done
, and an object consisting of:
Property | Value |
---|
type | String "set", denoting the event-type that was triggered |
prevState | the previous state |
nextState | the next state, after the event we are listening to |
Fires on: Setting extant properties; index accessors
Type (TypeScript only) VX_LISTENER_INTERNALS.SET
del
An element or property has been deleted. Callbacks will receive a function, done
, and an object consisting of:
Property | Value |
---|
type | String "del", denoting the event-type that was triggered |
prevState | the previous state |
nextState | the next state, after the event we are listening to |
Fires on: methods such as pop
; delete
called on a property
Type (TypeScript only) VX_LISTENER_INTERNALS.DEL
batched
A batched event has occurred. Batched events are those which carry several state changes as the result of a single action. For example, Array.prototype.unshift
may prepend an element and shifts each element.
Callbacks will receive a function, done
, and an object consisting of:
Property | Value |
---|
type | String "batched", denoting the event-type that was triggered |
prevState | the previous state |
nextState | the next state, after the event we are listening to |
Fires on: methods such as shift
, unshift
, push
when called with multiple elements
Type (TypeScript only) VX_LISTENER_INTERNALS.BATCHED
Methods
Methods bound to all vivisected
objects:
addEventListener (eventName: VX_EVENT_TYPE, handler: VxEventHandler, opts: { alwaysCommit?: boolean }) => VxEventedObject
Bind a callback to fire whenever a given event-type has been triggered.
Throws when: provided an invalid event type or non-function handler
Example:
const logMsg = function (event) {
console.log(`Added item such that ${event.prevState} becomes ${event.nextState}`);
});
const users = vivisect(['Alice','Bob']).addEventListener('add', logMsg);
users.push('Charlie');
removeEventListener (eventName: VX_EVENT_TYPE, handler: VxEventHandler, opts: { alwaysCommit?: boolean }) => VxEventedObject
Remove an existing callback from the respective event-type to which it has been registered.
Throws when: provided an invalid event type or non-function handler
Example:
const logMsg = function (event) {
...
});
const users = vivisect(['Alice','Bob'])
.addEventListener('add', logMsg, { alwaysCommit: true })
.removeEventListener('add', logMsg);
users.push('Charlie');
What's Next?
Next up for Vivisector is:
cancellable state mutations- deferred state mutations
- custom event types (bind specific methods to event handlers)