@chnn/tube

Easy state management for React apps

Usage no npm install needed!

<script type="module">
  import chnnTube from 'https://cdn.skypack.dev/@chnn/tube';
</script>

README

Tube

Easy state management for React, inspired by Redux and ember-concurrency.

Features:

  • Single source of truth
  • Immutable state updates / event sourcing pattern
  • Powerful concurrency primitives
  • Derived state (no more isLoading bookkeeping)
  • In-progress task cancellation

Design goals:

  • Ease of use
  • Lack of boilerplate
  • Type safety
  • Testable API design

Quickstart

Define your application state and initialize Tube's task and connect utilities:

// src/store.tsx

import initalize from "@chnn/tube"

interface AppState {
  count: number
}

const initialState: AppState = { count: 0 }

export const { task, connect } = initialize<AppState>(initialState)

Then connect components to your application state using task and connect:

// src/counter.tsx

import * as React from 'react'
import {TaskProp} from '@chnn/tube'

import * as api from "./api"
import { AppState, connect, task } from "./store"

interface Props {
  count: number
  onIncrement: TaskProp
}

const Counter: React.SFC<Props> = ({ count, onIncrement }) => (
  <div className="counter">
    <div className="value">
      Value: {onIncrement.isRunning ? <div className="loader" /> : count}
    </div>
    <button onClick={onIncrement}>+ Add 1</button>
  </div>
)

const increment = task(function*(getState) {
  const x = yield api.getCount(1) // Returns 1 after one second

  return { count: getState().count + x }
}).restartable()

const mapStateToProps = (state: AppState) => ({
  count: state.count
})

const mapTasksToProps = {
  onIncrement: increment
}

export default connect(
  mapStateToProps,
  mapTasksToProps,
  Counter
)

You can run this example yourself.