Nanoflux API

22 Apr 2016 . category: docs . Comments
#tutorial

API Overview

Provider API

Flux Component API

NanoFlux Provider API

The nanoflux high level API bases on factories, which provide all necessary components of the Flux architecture, i.e. Stores, Dispatcher, and Actions.

Store Provider

getStore( name )

Returns the store, or undefined, if not exists.

createStore( name, descriptor )

Creates a store with given name and descriptor.

The descriptor is a JSON object containing the store’s available methods and members. Keep in mind, that nanoflux maps actions to store functions using the following convention: actionName > onActionName

var store = NanoFlux.createStore('myStore', {
	__items : [],
	// will be mapped to action name 'addItem'
	onAddItem  : function(item){
		this.__items = this.__items.concat(Immutable(item));
		this.notify();
	}
});

Dispatcher Provider

getDispatcher( name? )

Returns the dispatcher, or undefined if not exists. If name is null or undefined, the built-in default dispatcher will be returned.

createDispatcher( name?, actionList? )

Creates a dispatcher with given name and an optional action name list. Passing null or undefined, refers to the built-in default dispatcher. The actionList is an array of action names, that are going to be available as actions in the dispatcher (‘fluxy’):

Examples Adds some actions directly (‘fluxy way’) to the default dispatcher

var dispatcher = NanoFlux.createDispatcher(null,['addItem', 'loadItems']);

// usage example
dispatcher.addItem( item );

Creates a custom dispatcher.

var myDispatcher = NanoFlux.createDispatcher('myDispatcher');

Action Provider

getActions( name )

Returns the action provider, or undefined if not exists.

createActions( name, dispatcher, actionDescriptor )

Creates actions with given name and descriptor using the given dispatcher. This is the typical way, as it offers full control of your actions. It is considered as best practice to access Web API (async calls) within the actions.

Keep in mind, that nanoflux maps actions to store functions using the following convention: actionName > onActionName

var dispatcher = NanoFlux.getDispatcher();
var myActions = NanoFlux.createActions('myActions', dispatcher, {
	addItem  : function(item){
		// will be mapped to store function 'onAddItem'
		this.dispatch('addItem', item);		
	},
	loadItems : function(){
		// async call - is a good practice to make web api calls on actions.
		itemService.getAll().then( function(items){
			this.dispatch('loadItems',items);
		}); 
	}
});

Middleware

use( func, dispatcher? )

Adds a middleware function to the given dispatcher (or the default dispatcher if not given). The function’s signature is fn(storeHandlerName, args), where storeHandlerName is the name of handler in the targeted store, and args the payload.

function Logger(){
    var log = [];

    return function(handlerName, args){
        log.push({
            handler: handlerName,
            payload : args
            }
        )
    }
}

// somewhere in your app --- using the fluxy approach for sake of simplicity
// ...
var dispatcher = NanoFlux.createDispatcher(null, ["action1", "action2"]);
NanoFlux.use(new Logger(), dispatcher);

dispatcher.action1({foo:"fromAction1"});
/* Log is:  [{handler: "onAction1", payload: [{foo:"fromAction1"}]}] */

dispatcher.action2({foo:"fromAction2"});
/* Final Log is:
    [
        {handler: "onAction1", payload: [{foo:"fromAction1"}]}
        {handler: "onAction2", payload: [{foo:"fromAction2"}]}
    ]
*/

Flux Component API

Each component of the Flux architecture provide additional methods, which are described here

Store

Inside a store’s descriptor the following methods are available for every instance.


onInitialization()

Within this method you can do some custom initialization on the store instance’s creation. A typical scenario would be the chaining of stores.

var store = NanoFlux.createStore('myStore', {
	__items : [],
	
	onAnotherStoreNotify: function(){
		// called when 'anotherStore' executes 'notify'
	}
	
	onInitialization: function(){
		var anotherStore = NanoFlux.getStore('anotherStore');
		// chain the stores
		anotherStore.subscribe(this, this.onAnotherStoreNotify);
	},
	
	onAddItem  : function(item){
		this.__items = this.__items.concat(Immutable(item));
		this.notify();
	}
});

notify( payload? )

Use notify to inform all subscribed views about state changes. Although, it is not common, it is possible to pass payload data as argument. Usually, a store maintains several states for certain context, that’s why payload won’t be passed on callback. But nanoflux is flexible enough to support even that.

var store = NanoFlux.createStore('myStore', {
	__items : [],

	// state getter
	getItems : function(){
		return this.__items;
	},
	
	onAddItem  : function(item){
		this.__items = this.__items.concat(Immutable(item));
		this.notify();
	}
});
var store = NanoFlux.createStore('myStore', {
	__items : [],		
	onAddItem  : function(item){
		this.__items = this.__items.concat(Immutable(item));
		// you may pass the state on callback
		this.notify(this.__items);
	}
});

subscribe( calleeContext, callbackFunc )

Creates a subscription and returns a subscription object. Once subscribed the subscriber callbackFunc is called on notify(). The calleeContext refers to the subscribers context and is bound to callbackFunc.

Use the returned subscription object to unsubscribe, e.g. while a component unmounts.

Note, that nanoflux offers the possibility to chain stores using subscribe (see onInitialization())

var MyComponent = React.createClass({

    myStore : NanoFlux.getStore('myStore'),

    getInitialState : function(){
        return { subscription : null, items : [] }
    },

	// the callback from store
    onStoreUpdated : function(){
         // through calleeContext I can access this components methods
        this.setState({ items : this.myStore.getItems() });
    },
    
    componentWillMount : function(){
        // start listening to store when view is mounted
        // passing calling context 'this' and the callback function
        this.state.subscription = this.myStore.subscribe(this, this.onStoreUpdated);
    },
    
    componentWillUnmount : function(){
        // unsubscribe
        this.subscription.unsubscribe();
    },

    render(){
        return (
            // ... your render stuff
        )
    }
});
var store = NanoFlux.createStore('myStore', {
	__items : [],		
	onAddItem  : function(item){
		this.__items = this.__items.concat(Immutable(item));
		// you may pass the state on callback
		this.notify(this.__items);
	}
});

Dispatcher

The Dispatcher is the central hub in a Flux architecture. nanoflux offers the possibility to use more than one dispatcher, if needed. Furthermore, with the nanoflux dispatcher you can attach simple, i.e. pure dispatch actions directly to the dispatcher, using a action name list on the dispatchers creation. This so called ‘fluxy’ approach, reduces boilerplate code significantly

Example

var dispatcher = NanoFlux.createDispatcher(null,['addItem', 'loadItems']);

// usage 
dispatcher.addItem(myItem);
dispatcher.loadItems();

connectTo(store|arrayOfStores)

Establish connection between a dispatcher instance and one or more stores. Once connected, the dispatcher is able to pass an action call towards its mapped store callback function.

Usually, multiple stores are connected to a single dispatcher, but it is also possible to connect one store to multiple dispatcher.

Tipp: Try to keep the setup as simple as possible, i.e. one dispatcher and several stores. Think twice, if you plan to introduce another dispatcher, or even chain a store.

Example

var dispatcher = NanoFlux.createDispatcher(null,['addItem', 'loadItems']);
var myStore = NanoFlux.getStore('myStore');
var anotherStore = NanoFlux.getStore('anotherStore');

// usage example one dispatcher -> many stores
dispatcher.connectTo( [myStore,anotherStore] );

dispatch(actionName, payload?)

Executes a dispatch, and is usually called inside an action.

The actionName is used for the action-store-mapping. It is common, to use the same name as the function’s name. nanoflux maps actions to store functions using the following convention: actionName > onActionName. The payload will be passed as argument directly to the store’s method.

Usually, you won’t call this method directly, but use the Action Provider instead.

Example

var dispatcher = NanoFlux.getDispatcher();
dispatcher.dispatch('actionName', {
	foo: 1,
	bar : "payload"
});

Action Provider

dispatch(actionName, payload?)

When using the conventional Flux approach (using the Action Provider Factory ) the created instance provides the Dispatcher.dispatch() function.

Example

var dispatcher = NanoFlux.getDispatcher();
var myActions = NanoFlux.createActions('myActions', dispatcher, {
	addItem  : function(item){
		// will be mapped to store function 'onAddItem'
		this.dispatch('addItem', item);		
	},
	loadItems : function(){
		// async call - it is a good practice to make web api calls on actions.
		itemService.getAll().then( function(items){
			this.dispatch('loadItems',items);
		}); 
	}
});