npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

condensate

v0.1.0-alpha.1

Published

Application state management inspired by Om and Clojure.

Downloads

3

Readme

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

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. 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. This is done by passing a transaction 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 new replacement value. doTransact returns a transaction object, which has a commit method and cancel method.

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 sugar update functions are actually implemented on top of the base doTransact function and automatically call commit.

Cursors

Managing state from a root atom would seem to severely restrict our ability to build modular components. The 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 their node. 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 code 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.