All Projects → alloc → vana

alloc / vana

Licence: MIT license
Observe your immutable state trees 🌲👀 (great with React)

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to vana

grand central
State-management and action-dispatching for Ruby apps
Stars: ✭ 20 (-16.67%)
Mutual labels:  immutable, state-management
dobux
🍃 Lightweight responsive state management solution.
Stars: ✭ 75 (+212.5%)
Mutual labels:  immutable, state-management
Mobx State Tree
Full-featured reactive state management without the boilerplate
Stars: ✭ 6,317 (+26220.83%)
Mutual labels:  state-management, observable
mutable
State containers with dirty checking and more
Stars: ✭ 32 (+33.33%)
Mutual labels:  state-management, observable
Reim
🤔 Handle logic in frontend
Stars: ✭ 79 (+229.17%)
Mutual labels:  immutable, state-management
micro-observables
A simple Observable library that can be used for easy state management in React applications.
Stars: ✭ 78 (+225%)
Mutual labels:  state-management, observable
Observable Slim
Observable Slim is a singleton that utilizes ES6 Proxies to observe changes made to an object and any nested children of that object. It is intended to assist with state management and one-way data binding.
Stars: ✭ 178 (+641.67%)
Mutual labels:  state-management, observable
reactive state
An easy to understand reactive state management solution for Flutter.
Stars: ✭ 19 (-20.83%)
Mutual labels:  state-management, observable
Utility
Assign/Partial/ReadOnly/Proxy
Stars: ✭ 31 (+29.17%)
Mutual labels:  immutable, observable
Easy Peasy
Vegetarian friendly state for React
Stars: ✭ 4,525 (+18754.17%)
Mutual labels:  immutable, state-management
mst-effect
💫 Designed to be used with MobX-State-Tree to create asynchronous actions using RxJS.
Stars: ✭ 19 (-20.83%)
Mutual labels:  state-management, observable
Bistate
A state management library for React combined immutable, mutable and reactive mode
Stars: ✭ 113 (+370.83%)
Mutual labels:  immutable, state-management
Mag.js
MagJS - Modular Application Glue
Stars: ✭ 157 (+554.17%)
Mutual labels:  state-management, observable
zedux
⚡ A high-level, declarative, composable form of Redux https://bowheart.github.io/zedux/
Stars: ✭ 43 (+79.17%)
Mutual labels:  immutable, state-management
Freezer
A tree data structure that emits events on updates, even if the modification is triggered by one of the leaves, making it easier to think in a reactive way.
Stars: ✭ 1,268 (+5183.33%)
Mutual labels:  immutable, state-management
Model
Angular Model - Simple state management with minimalist API, one way data flow, multiple model support and immutable data exposed as RxJS Observable.
Stars: ✭ 242 (+908.33%)
Mutual labels:  immutable, state-management
vuse-rx
Vue 3 + rxjs = ❤
Stars: ✭ 52 (+116.67%)
Mutual labels:  state-management
extendable-immutable
Wrapper classes around Immutable.js that turn it inheritable
Stars: ✭ 58 (+141.67%)
Mutual labels:  immutable
xoid
Framework-agnostic state management library designed for simplicity and scalability ⚛
Stars: ✭ 96 (+300%)
Mutual labels:  state-management
observable-profiler
Tracks new & disposed Observable subscriptions
Stars: ✭ 41 (+70.83%)
Mutual labels:  observable

npm Build status codecov Bundle size Code style: Prettier Donate

Observe your immutable state trees.

Vana adds observability to normal objects without mutating their public appearance. The only exception to that rule is that all objects are made immutable. This is Vana at its core.

 

Read the introduction.

 

Basic usage

import { o } from 'vana'

let state = o({
  /* Any data can go here */
})

The returned state is immutable and observable.

Before we make any changes, let's observe our state object:

import { tap } from 'vana'

// This callback is called synchronously whenever `state` changes.
tap(state, newState => {
  state = newState
})

The first kind of mutation passes a callback to the revise function. Any changes made within the callback are used to create an immutable copy of our state object.

import { revise } from 'vana'

const base = state
const copy = revise(state, draft => {
  /* Mutate our immutable state in here */
})

assert(base !== copy)
assert(copy === state) // Our `state` variable is updated.

The copy object is now observed by whoever was observing the base object, and revising the base object is now forbidden.

The second kind of mutation passes an object to the revise function. This is essentially the Object.assign of Vana.

const copy = revise(state, {
  /* Any data can go here */
})

Those are the basics. Here is a sandbox you can play with:

https://codesandbox.io/s/z33pzx31wp

https://github.com/alloc/vana-sandbox

 

Install

yarn add vana

 

Integrations

 

Advanced usage

Here are some advanced use cases.

Cloning an observable object

Clone an observable object by passing it to the o function.

const base = o({ a: 1 })
const copy = o(base)

// The "copy" has its own observable identity.
assert(isObservable(copy))
assert(base !== copy)

// The "base" is still observable and revisable.
assert(isObservable(base))
tap(base, console.log)
revise(base, { a: 2 })

 

Controlled observables

Pass a callback to the o function to create a controlled observable.

// This pattern is great for memoized subscriptions.
const foo = o<number>(next => {
  next(0) // Always provide an initial value.
  let n = 0
  let id = setInterval(() => next(++n), 1000)
  return () => clearInterval(id)
})
// Log every new value.
foo.tap(console.log)

 

The latest function

Give any value and receive the latest revision (if possible), else return it as-is.

const o1 = o({ foo: true })
const o2 = revise(o1, { foo: false })
const o3 = revise(o2, { foo: true })

assert(o1 !== o3)
assert(latest(o1) === o3)

// Trash in, trash out
assert(latest(1) === 1)

 

The keepAlive function

Use the keepAlive function to make a "living" object out of an observable object. The returned object is a mirror of the observable's current value.

import { keepAlive } from 'vana'

let initialState = o({ a: 1 })
let state = keepAlive(initialState)

// The latest revision is always reflected
const lastState = revise(initialState, { a: 2 })
assert(state.a === 2)

// Can be passed to `latest`
assert(latest(state) === lastState)

// Be sure to call dispose when appropriate
state.dispose()

 

The watch function

This function lets you watch any property path in a state tree.

import { watch } from 'vana'

// An observable that updates when `obj.a.b.c` is changed
const prop = watch(obj).a.b.c

// Run a function when the property value is changed
const observer = prop.tap(console.log)

// Get the current property value
prop.get()

// Shallow properties can be observed more efficiently
const prop = watch(obj, 'a')

// You can use a selector function if you want
const prop = watch(obj, obj => obj.a.b.c)

Every property in the path is observed.

The property value is deeply observed if possible.

 

Array helpers

These functions are for working with immutable arrays. Each function works for any array regardless of mutability. They always return a modified copy of the given array (or the given array if no changes were made).

import { append, prepend, insert, concat, remove } from 'vana'

// Append one or more values to a copy of the given array.
append(arr, ...values)

// Prepend one or more values to a copy of the given array.
prepend(arr, ...values)

// Insert one or more values into a copy of the given array.
insert(arr, index, ...values)

// Merge one or more arrays into a copy of the given array.
concat(arr, ...values)

// Remove one or more values from a copy of the given array.
remove(arr, index, (count = 1))

 

Custom immutable classes

Any class can be made compatible with Vana's cloning logic.

import { immerable, o, revise, keepAlive, latest } from 'vana'

class Foo {
  readonly bar: number = 0

  // Let `Foo` instances be assumed readonly
  static [immerable] = true

  // Mutate yourself with `revise`
  setBar(bar: number) {
    return revise(this, { bar })
  }
}

let foo = o(new Foo())
assert(Object.isFrozen(foo))
assert(foo.bar === 0)

foo = foo.setBar(1)
assert(foo.bar === 1)

// works with `keepAlive`
const fooLatest = keepAlive(foo)

const foo3 = foo.setBar(2)
assert(foo3 !== foo)
assert(foo3.bar === 2)
assert(fooLatest.bar === 2)

// and with `latest`
foo = latest(foo)
assert(foo === foo3)

 

TODO: Provide more advanced use cases

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].