Skip to content

Latest commit

 

History

History
453 lines (312 loc) · 11.3 KB

api.md

File metadata and controls

453 lines (312 loc) · 11.3 KB

Storefront

Getting the Storefront object...

If you're using a CommonJS system (browserify/webpack):

var Storefront= require( 'storefront')

If you are using Bower, Storefront is available as a global.

In theory, Require.js and/or AMD modules are supported as well -- But they're completely untested.

Storefront Static API

Storefront.configure( settings:object )

Settings object:

name default description
asyncDispatch true Defer dispatching from action creator to nextTick.
freezeInstance false Use Object.freeze on instance after definition.
logging false Log all dispatches to the console.
useRAF true Batch top-level onChange event using requestAnimationFrame.
verbose false Prints warnings to console.
singletonDispatcher false Use a global dispatcher instead of a shared-runtime instance.

Storefront.define( name:string, builder:function )

Defines a store:

Storefront.define( 'StoreName', manager =>{

    // Object keys sent to .actions() become action names
    manager.actions({

        actionName( action ) {
            // action === {
            //     origin: 'StoreName',
            //     type: 'StoreName_actionName',
            //     payload: { params }
            // }

            // You can wait for other Stores to complete their
            // dispatch handling like this:
            manager.waitFor( 'OtherStore' )

            // Or...
            var otherStore= manager.get( 'OtherStore' )
            manager.waitFor( otherStore )

            // After you have changed your internal data
            // structures, trigger change event
            manager.hasChanged()

            // If you want to send a notify event
            manager.notify( 'A message.' )
        }
    })


    // Create your own "Action Creators"
    manager.before({

        actionName( dispatch, params ) {
            // dispatch() is auto-bound with the action name,
            // 'StoreName_actionName' in this case.

            // Just send the payload to the dispatcher:
            dispatch({ params })
        }
    })


    // Provide data accessor methods for public consumption
    manager.outlets({
        // Available on the storefront instance
        getSomething() {}
    })

    // Listen to actions from other other stores
    manager.observes( 'OtherStore', {
        // Match the action name/mthod of other store
        otherActionName( action ) {
            // You can send the name of the store to wait for, or get
            // an instance with: manager.get( 'OtherStore' )
            manager.waitFor( 'OtherStore' )
        }
    })

})

Storefront.get( name:string )

Retrieves a defined store.


Storefront.onChange( fn:function )

Storefront aggregates all defined stores' onChange events into a single top-level change event. By default, it will use requestAnimationFrame to schedule event delivery.


Storefront.offChange( fn:function )

Stops listening to aggregated change event.


Storefront.newInstance()

Returns a new Runtime (Storefront instance) configured with the same settings, but none of the store definitions.


Storefront Manager API

The store builder function will be called with an instance of a Manager. This is what you'll use to define your store's API (actions, outlets, observations, etc.).


manager.actions( methods:object )

Define actions that this store will handle. "Action Creators" are automatically created and look like this:

stubbed_action_creator= ()=> {
    var args= Array.prototype.slice.call( arguments ),
        dispatch= args.shift()
    if( args.length === 1 )
        dispatch( args[ 0] )
    else
        dispatch( args )
}

manager.before( methods:object )

Define custom "Action Creators."


manager.createEvent( name:string )

Create a custom store event. See Custom Events, below.


manager.get( name:string )

Returns a store instance by name.


manager.hasChanged()

Trigger an onChange event. You need to call this whenever your store's internal data structures have changed.


manager.invoke( outletOrAction:string|object, ...params:any[] )

Call an outlet or action method on the store instance.


manager.notify( data:any )

Trigger a Notify event.


manager.observes( storeOrName:string|object, methods:object )

Listen for actions on other stores.


manager.outlets( methods:object )

Properties specified are created on the store instance.


manager.waitFor( storeOrName:string|object )

Sequences dispatching so that the store specified will have handled the action before this method returns.


Storefront Instance API

In addition to the outlets and actions defined in stores, storefront instances also have these properties defined:

// Get a store instance by name...
var store= Storefront.get( "StoreName" )

store.name:string

The name of the store.


store.onChange( fn:function )

Listen for changes on store instance. Not batched.

Returns unsubscription function.

let stopListening= store.onChange( ()=> alert( 'bang' ) )
// When you're ready:
stopListening()

store.offChange( fn:function )

Stop listening for changes.


store.onNotify( fn:function )

Listen for notifications.


store.offNotify( fn:function )

Stop listening for notifications.


store.token:string

The token used by the Dispatcher. Primarily for internal use.


Action Stubbing

Storefront will automatically create an action stub for every method defined in the actions block:

Storefront.define( 'Timer', mgr => {
    const {actions, outlets, dataHasChanged} = mgr

    let _timer = {
        active: false,
        started: null
    }

    // Just define the 'actions' and the actions will be auto-stubbed
    actions({
        start( action ) {
            _timer.active = true
            _timer.started = +new Date
            dataHasChanged()
        },

        stop( action ) {
            _timer.active = false
            _timer.started = 0
            dataHasChanged()
        }
    })

    outlets({
        duration() {
            var now = +new Date
            return now - _timer.started
        }
    })
})

To implement your own "Action Creators," use the before block. It will be provided a dispatch function as the first argument. That function is pre-bound to trigger the correct action, so you just call it with your payload.

This is the same Timer example store as above, only it intercepts the start action and only dispatches it if the timer isn't already running.

Storefront.define( 'Timer', mgr => {
    const {actions, outlets, dataHasChanged} = mgr

    let _timer= {
        active: false,
        started: null
    }

    before({
        start( dispatch ) {
            if( _timer.active === false ) {
                dispatch() // carry on
            }
            else {
                console.log( "Timer already started!")
                // dispatch isn't called!
            }
        }
    })

    actions({
        start( action ) {
            _timer.active = true
            _timer.started = +new Date
            dataHasChanged()
        },

        stop( action) {
            _timer.active = false
            _timer.started = 0
            dataHasChanged()
        }
    })

    outlets({
        duration() {
            var now = +new Date
            return now - _timer.started
        }
    })
})

Custom Events

You can define custom events in your store by calling storeManager.createEvent( name ). Once defined, store instances have onXXX and offXXX methods (where XXX is the event name). Example:

var store= Storefront.define( 'Hotkey', mgr => {
    const emitHotkey= mgr.createEvent( 'hotkey' )

    /// Somewhere in your code:
    emitHotkey( params )
})

// Instances now have support for:
store.onHotkey( fn )
store.offHotkey( fn )

Event Helper Mixin

Storefront provides a helper mixin that will register store event listeners and automatically deregister them at the componentWillUnmount lifecycle hook.

It creates the helper method: onStoreEvent( storeName, eventName, callback )

Usage:

React.createClass({
    mixins: [ Storefront.util.eventHelperMixin ],

    componentDidMount() {
        this.onStoreEvent(
            "Auth",                // Store name or Store instance
            "ValidationError",     // Event name
            this.onValidationError // Handler
        )
    }
})

The event helper mixin is a thin wrapper around:


Subscription Manager

A utility for managing event subscriptions. Use it in a class-based React component like this:

class MyComponent extends React.Component {
    componentDidMount() {
        this._subscriptions= Storefront.util.subscriptions()
            .on( 'MyStore', 'notify', this.onStoreNotification.bind( this ))
    }
    
    componentWillUnmount() {
        this._subscriptions.release()
    }

    onStoreNotification( notice ) {
        // Do something with it here...
    }

    render() {
        return (
            <div></div>
        )
    }
}