BEYOND FLUX BEYOND FLUX SCALABLE FRONTEND ARCHITECTURES SCALABLE FRONTEND ARCHITECTURES USING PUBLISH/SUBSCRIBE USING PUBLISH/SUBSCRIBE Michael Kurze @ goto Amsterdam 2016 1
WHY ARCHITECTURE? WHY ARCHITECTURE? IT'S ABOUT TIME! IT'S ABOUT TIME! JS Transfer / kB 400 - 300 - 200 - 100 - 0 - 2011-04-01 2012-10-12 2014-05-13 2016-04-01 (Source: httparchive.org) We are building complex so fu ware (requires tools) , and we are talking about them (requires a language) . 2
COMPLEXITY COMPLEXITY PLATFORM COMPLEXITY PLATFORM COMPLEXITY DRIVING DRIVING APPLICATION COMPLEXITY APPLICATION COMPLEXITY 3
REACTIVITY & RESPONSIVENESS REACTIVITY & RESPONSIVENESS synchronize state (across devices) provide immediate feedback continuous bi-directional communication (client/server) http://www.reactivemanifesto.org 4
SCALEABILITY SCALEABILITY 5
UNIDIRECTIONAL FLOW UNIDIRECTIONAL FLOW 6
ONCE UPON A TIME ... ONCE UPON A TIME ... UI inconsistencies in Facebook chat 7
FLUX FLUX 8
FLUX - EXAMPLE FLUX - EXAMPLE https://github.com/voronianski/flux-comparison 10
FLUX - EXAMPLE - VIEW (1/3) FLUX - EXAMPLE - VIEW (1/3) var React React = = require require( ('react' 'react') ); ; var var var FluxibleMixin FluxibleMixin = = require require( ('fluxible' 'fluxible') ). .FluxibleMixin FluxibleMixin; ; var ProductStore ProductStore = = require require( ('./stores/ProductStore' './stores/ProductStore') ); ; var var var addToCart addToCart = = require require( ('./actions/addToCart' './actions/addToCart') ); ; var var Products Products = = React React. .createClass createClass( ({ { mixins: : [ [FluxibleMixin FluxibleMixin] ], , mixins render render: : function function( () ) { { return return < <ul ul> > { {this this. .state state. .products products. .map map( (product product = => > < <li li> > < <img img src src= ={ {product product. .image image} }/> /> { {product product. .title title} } - - { {product product. .price price} } € € < <button button onClick onClick= ={ {( () ) = => > this this. .addToCart addToCart( (product product) )} } disabled disabled= ={ {product product. .inventory inventory === === 0 0} }> >add add</ </button button> > </ </li li> > ) )} } </ </ul ul> >; ; } }, , addToCart addToCart: : function function( (product product) ) { { this this. .executeAction executeAction( (addToCart addToCart, , { { product product: : product product } }) ); ; } }, , // ... // ... }) ); ; } 11 . 1
FLUX - EXAMPLE - VIEW (2/3) FLUX - EXAMPLE - VIEW (2/3) var var React React = = require require( ('react' 'react') ); ; var var FluxibleMixin FluxibleMixin = = require require( ('fluxible' 'fluxible') ). .FluxibleMixin FluxibleMixin; ; var var ProductStore ProductStore = = require require( ('./stores/ProductStore' './stores/ProductStore') ); ; var var addToCart addToCart = = require require( ('./actions/addToCart' './actions/addToCart') ); ; var var Products Products = = React React. .createClass createClass( ({ { // ...render, addToCart... // ...render, addToCart... getInitialState getInitialState: : function function( () ) { { return return this this. ._getStateFromStores _getStateFromStores( () ); ; } }, , _getStateFromStores: : function function( () ) { { _getStateFromStores return return { { products: : this this. .getStore getStore( (ProductStore ProductStore) ). .getAllProducts getAllProducts( () ) products } }; ; } }, , statics: : { { statics storeListeners storeListeners: : { { _onChange: : [ [ProductStore ProductStore] ] _onChange } } } }, , _onChange: : function function( () ) { { _onChange this this. .setState setState( (this this. ._getStateFromStores _getStateFromStores( () )) ); ; } } }) } ); ; 11 . 2
FLUX - EXAMPLE - VIEW (3/3) FLUX - EXAMPLE - VIEW (3/3) var var React React = = require require( ('react' 'react') ); ; var var FluxibleMixin FluxibleMixin = = require require( ('fluxible' 'fluxible') ). .FluxibleMixin FluxibleMixin; ; var var ProductStore ProductStore = = require require( ('./stores/ProductStore' './stores/ProductStore') ); ; var var addToCart addToCart = = require require( ('./actions/addToCart' './actions/addToCart') ); ; var Products var Products = = React React. .createClass createClass( ({ { /* ... */ /* ... */ } }) ); ; var var ShoppingCart ShoppingCart = = require require( ('./components/CartContainer.jsx' './components/CartContainer.jsx') ); ; var var App App = = React React. .createClass createClass( ({ { mixins: mixins : [ [FluxibleMixin FluxibleMixin] ], , render: render : function function( () ) { { return return < <div div> > < <Products Products /> /> < <ShoppingCart ShoppingCart /> /> </ </div div> >; ; } } } }) ); ; export export function function render render( (context context) ) { { React. .withContext withContext( ( React context context. .getComponentContext getComponentContext( () ), , function function( () ) { { React. React .render render( ( React. .createElement createElement( (App App) ), , React document. document .getElementById getElementById( ('fluxible-app' 'fluxible-app') ) ) ); ; } } ) ); ; } } 11 . 3
FLUX - EXAMPLE - ACTION FLUX - EXAMPLE - ACTION var var shop shop = = require require( ('../../../api/shop' '../../../api/shop') ); ; // actions/addToCart.js // actions/addToCart.js module. module .exports exports = = function function ( (context context, , payload payload, , done done) ) { { context. context .dispatch dispatch( ('ADD_TO_CART' 'ADD_TO_CART', , { { product product: : payload payload. .product product } }) ); ; done done( () ); ; }; ; } // actions/cartCheckout.js // actions/cartCheckout.js module module. .exports exports = = function function ( (context context, , payload payload, , done done) ) { { var var products products = = payload payload. .products products; ; context. .dispatch dispatch( ('CART_CHECKOUT' 'CART_CHECKOUT') ); ; context shop. .buyProducts buyProducts( (products products, , function function ( () ) { { shop context context. .dispatch dispatch( ('SUCCESS_CHECKOUT' 'SUCCESS_CHECKOUT', , { { products products: : products products } }) ); ; done done( () ); ; } }) ); ; }; ; } 12
FLUX - EXAMPLE - DISPATCHER FLUX - EXAMPLE - DISPATCHER var Fluxible Fluxible = = require require( ('fluxible' 'fluxible') ); ; var var var CartStore CartStore = = require require( ('./stores/CartStore' './stores/CartStore') ); ; var ProductStore ProductStore = = require require( ('./stores/ProductStore' './stores/ProductStore') ); ; var var app app = = new new Fluxible Fluxible( () ); ; var app. app .registerStore registerStore( (CartStore CartStore) ); ; app. .registerStore registerStore( (ProductStore ProductStore) ); ; app var var view view = = require require( ('./view' './view') ) var receiveProducts receiveProducts = = require require( ('./actions/receiveProducts' './actions/receiveProducts') ); ; var var var context context = = app app. .createContext createContext( () ); ; context context. .executeAction executeAction( (receiveProducts receiveProducts, , { {} }, , function function ( (err err) ) { { if if ( (err err) ) { { throw throw err err; ; } } return return view view. .render render( (context context) ); ; }) } ); ; 13
FLUX - EXAMPLE - STORES FLUX - EXAMPLE - STORES var var createStore createStore = = require require( ('fluxible/addons/createStore' 'fluxible/addons/createStore') ); ; var ProductStore ProductStore = = createStore createStore( ({ { var storeName storeName: : 'ProductStore' 'ProductStore', , initialize: : function function ( () ) { { initialize this this. ._products _products = = [ [] ]; ; } }, , handlers: : { { handlers 'ADD_TO_CART' 'ADD_TO_CART': : 'decreaseInventory' 'decreaseInventory', , 'RECEIVE_PRODUCTS' 'RECEIVE_PRODUCTS': : 'handleReceive' 'handleReceive' } }, , handleReceive handleReceive: : function function ( (payload payload) ) { { this this. ._products _products = = payload payload. .products products; ; this this. .emitChange emitChange( () ); ; } }, , decreaseInventory decreaseInventory: : function function ( (payload payload) ) { { this this. .dispatcher dispatcher. .waitFor waitFor( ('CartStore' 'CartStore', , function function( () ) { { var var product product = = payload payload. .product product; ; product product. .inventory inventory = = Math Math. .max max( (product product. .inventory inventory-1 -1, , 0 0) ); ; this this. .emitChange emitChange( () ); ; } }) ); ; } }, , getAllProducts: getAllProducts : function function ( () ) { { return return this this. ._products _products; ; } } } }) ); ; module. module .exports exports = = ProductStore ProductStore; ; 14
Recommend
More recommend