GithubHelp home page GithubHelp logo

condensate's Introduction

Travis CI status icon

What?

Condensate is a super cool library for managing application state inspired by Om, Clojure, Bose and Einstein.

It provides a lightweight atom (inspired by Clojure) and cursor (inspired by Om) implementation to enable robust and low ceremony coordination of application state changes. Actual state data is stored using the excellent Immutable.js library.

Though designed to be used in the context of a React application, no actual dependency exists on React, and an attempt has been made to keep the scope restricted to state management.

Why?

Much has already been written about the benefits of immutable data and careful management of state changes. For now I'll refer you to a few excellent talks:

Installation

Available via npm install condensate or bower install condensate.

Currently, Condensate is available as raw, untranspiled ES6. Webpack and Babel are highly recommended, though I'm not opposed to distributing a transpiled-to-ES5 version in the future. See the examples/webpack.config.js for a working example.

Usage

Basics

import Atom from 'condensate'
import Immutable from 'immutable'
var atom = new Atom()

The initial value defaults to an empty Immutable.Map, but you can pass in your own via the first parameter.

atom = new Atom(Immutable.Map({number: 1}))

The current value of the atom is available via the value property:

atom.value.get('number') === 1

An Atom has update methods based on Immutable's API, each prefixed with "do":

atom.doSet('number', 2)
atom.doUpdate('number', n => n + 1)
atom.value.get('number') === 3

Transactions

Many state transitions must be coordinated with asynchronous requests to the server. Rather then waiting for the full round trip to succeed, Condensate allows you to optimistically apply the change using a transaction by passing a function to doTransact.

const transaction = atom.doTransact(function(value) {
  return value.set('number', 4)
})
atom.value.get('number') === 4

The function will receive the current value and must return a replacement value. doTransact returns a transaction object containing commit and cancel methods.

setNumberOnServerWithAjax(4)
  .then(transaction.commit)
  .catch(transaction.cancel)

The transaction function is placed in a queue and applied to the state immediately. You can then commit or cancel the transaction depending on the response from the server. If the transaction is canceled, the function will be removed and the state will be rolled back. Any other transactions which come later in the queue will be reapplied.

A transaction function must be pure, as it may be called repeatedly based on results of other transactions that preceed it.

The other update functions are actually implemented on top of the base doTransact function and automatically call commit for you.

Cursors

Managing state from a root atom would seem to severely restrict our ability to build modular components. Condensate's Om inspired solution is to allow cursors to be derived from the root atom.

atom = new Atom(Immutable.fromJS({nested: {letter: 'a'}}))
var cursor = atom.cursor(['nested'])
cursor.value.get('letter') === 'a'

Cursors maintain an internal reference to their root atom along with a path to an inner node in the tree. The Cursor API is identical the Atom API, and you can even derive deeper cursors if needed. Changes made to the cursor's value will be reflected in the root atom.

cursor.doSet('letter', 'b')
atom.value.getIn(['nested', 'letter']) == 'b'

The idea is that you can create modular components that only depend on being passed an atom or cursor which they can update as appropriate without being coupled to a specific overall data structure.

Subscriptions

A simple subscription API enables straightforward and flexible integration. Subscribing functions will only be called when the relevant value changes.

var cancel = atom.subscribe(function(value, oldValue) {
  console.log(value)
})
// ... later
cancel()

Subscriptions can be scoped using a path array. Cursors automatically prefix the path of their subscribers with the path of the cursor.

atom.subscribe(['nested'], function(value, oldValue) {
  console.log(value)
})

// ... is identical to ...

cursor.subscribe(function(value, oldValue) {
  console.log(value)
})

Stability

I've been using it on a few unreleased early stage projects with great success, but I want to let it bake for a bit to ensure everything is conceptually sound before stamping a beta or higher version on it.

The basic (and intentionally narrow) scope of the project is largely in place, with no major functionality currently planned for the core library. I do intend to add a few extras, primarily around integration helpers for other projects such as React and react-router.

There are also some potential optimizations and a few design decisions around error handling that will need to occur, but as of now there are no known glaring issues.

condensate's People

Contributors

tgecho avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.