apostate

Reactive state management.

Usage no npm install needed!

<script type="module">
  import apostate from 'https://cdn.skypack.dev/apostate';
</script>

README

Experimental

Apostate is an experiment in reactive application-state management.

Adds approximately 2.6Kb to your client-side bundle, when compiled and minified using a bundler such as webpack.

Routing

Apostate exposes express-style routing, via adapters. Each route has one or more handler, with a signature function( req, res, next ) { ... }. Several Apostate-specific methods are exposed via the req and res objects.

const router = Router({ adapter });

router.get( '/', ( req, res ) => {
  const tasks = [
    { label: 'Clean the gutters.', completed: false },
    { label: 'Pickup milk', completed: false }
  ];

  res.dispatch( state => {
    state.set( 'tasks', Immutable.fromJS( tasks ) );

    res.completed()
  });
});

Anonymous Actions

res.dispatch( state => {
  state.set( 'status', 'completed' );
});

Named Actions

engine.register( 'status:update', ( state, params ) => {
  state.set( 'status', params.status );
});

res.dispatch( 'status:update', { status: 'completed' });

Express (Server)

import Immutable from 'immutable';
import { Observable } from 'rx/dist/rx.all';

import express from 'express';

import Engine from 'apostate/engine';
import Router from 'apostate/router';
import ExpressAdapter from 'apostate/adapters/express';

const app = express();

function initialize( req ) {
  const state = Immutable.fromJS({
    // ...
  });

  return Observable.return( state );
}

function render( state ) {
  const content		= React.renderToString( React.createElement( App, { state } ) );
    const document	= React.renderToStaticMarkup( React.createElement( Document, { content, state }) );

    const status = state.get( 'status', 200 );

    return { status, document };
}

const actions = {
  'feed:load': function( state, { done }) {
    done();
  }
}

const router = Router({ adapter: ExpressAdapter({ app, Engine, initialize, render, config: { actions } }) });

router.get( '/', ( req, res ) => {
  const { dispatch } = res;

  const href = ( typeof location != 'undefined' ) ? location.href : '/';
  const network = req.state.getIn( ['session', 'user'] ) ? 'personal' : 'featured';

  dispatch( state => {
    state.delete( 'overlay' );
    state.set( 'page', Immutable.fromJS({ base: 'home', title: "Home | This.", filters: { network } }) );

    res.completed()
  });

  dispatch( 'feed:load', { network, done: res.completed });
});