bidirecional flux: o fim do data-binding - qconsp · 2016-08-26 · two-way-binding november, 2nd,...
TRANSCRIPT
FLUX: O FIM DO DATA-BINDING BIDIRECIONAL
Oliver Häger
Contexto Onde encaixa o tópico
Cont
exto
‘Novo’ paradigma: Orientado ao componentes
Cont
exto
polymer
angular2
aurelia
react
flight
Cont
exto
Mostrar custom elementvar ShopApp = React. createClass({ render: function () { return ( <BasePage> <div className="grid"> <div className="grid__cell grid__cell" > <ShopMenu mountto="#shopcanvas" /> </div> </div> <div className="grid"> <div className="grid__cell grid__cell--width-70" > <div id="shopcanvas"> <ProductContainer/> </div> </div> <div className="grid__cell grid__cell" > <CartContainer/> </div> </div> </BasePage> ) }});
React Example
Cont
exto
ObjetivoAlguem disse “Flux”?
Obj
etiv
o
Flux é um padrão arquitetural para estabelecer fluxo de dados unidirecional entre componentes.
Obj
etiv
o
whY?
Obj
etiv
o
Flux (by Facebook)
Obj
etiv
o
Entenda porque há necessidade de um conceito como Flux no mundo de aplicativos web baseados em componentes.
Two-way-bindingExcurso: Uma técnica desvanecendo
Two-
way
-bin
ding
Two-
way
-bin
ding
Comfortável, mas caro:- Verificar modelos complexos- Verificar muitos modelos
Two-
way
-bin
ding
Rastreamento do modelo- Ciclo de monitoramento
- p.e. Digest-cycle ($apply)
- Algoritmo de comparação- p.e. JSON.stringify(), ou
percorrer propriedades manualmente
Two-
way
-bin
ding
Object.observe()?(funcão nativa para monitoramento de objetos)
Two-
way
-bin
ding
November, 2nd, 2015
https://esdiscuss.org/topic/an-update-on-object-observe
Two-
way
-bin
ding
November, 2nd, 2015
After much discussion with the parties involved, I plan to withdraw the Object.observe proposal from TC39 (where it currently sits at stage 2 in the ES spec process), and hope to remove support from V8 by the end of the year (the feature is used on 0.0169% of Chrome pageviews, according to chromestatus.com).
https://esdiscuss.org/topic/an-update-on-object-observe
Two-
way
-bin
ding
Mostrar custom elementvar TwoWay = React. createClass({ getInitialState : function() { return {message: this.props.message}; },
componentWillReceiveProps : function(nextProps){ if(this.state.message !== nextProps. message){ this.setState({message: nextProps.message}); } },
handleChange: function(event) { this.setState({message: event.target.value});
if(this.props.onChange){ this.props.onChange(event);
} }, render: function() { var message = this.state.message; return <input type="text" value={message} onChange={this.handleChange} />; }});
React Two-Way-Binding
Two-
way
-bin
ding
2. Fluxo unidirecional Uma abstração evolutiva
Abs
traç
ão
Abs
traç
ão
Mostrar custom elementvar ShopApp = React. createClass({ render: function () { return ( <BasePage> <div className="grid"> <div className="grid__cell grid__cell" > <ShopMenu mountto="#shopcanvas" /> </div> </div> <div className="grid"> <div className="grid__cell grid__cell--width-70" > <div id="shopcanvas"> <ProductContainer/> </div> </div> <div className="grid__cell grid__cell" > <CartContainer/> </div> </div> </BasePage> ) }});
React Example
Abs
traç
ão
Data Binding entre componentes
Abs
traç
ão
Mostrar custom elementvar ProductListContainer = React. createClass({
getInitialState : function(){ return {products : []} },
onProductsChanged : function(products){ this.setState( {products : products}); if(this.props.onChanged){ this.props.onChanged(products) ; } },
componentWillMount : function(){ ShopService. loadProducts().then(this.onProductsChanged ); },
render: function () { return ( <ProductList products={this.state.products}/> ); }});
React Example
Abs
traç
ão
Data Binding com componentes
Abs
traç
ão
Data Binding com componentes
Abs
traç
ão
Propagação de dados entre os componentes é complexo e não escala
Usar eventos não resolve pois também não escala
Abs
traç
ão
Extrair o estado para fora dos componentesA
bstr
ação
O Store mantem modelos, sabe atualizá-los e notifica os componentes
Abs
traç
ão
Mostrar custom element
var shopStore = FooFlux. createStore({ id : 'shopStore', _products : [], getProducts : function(){
return _.cloneDeep(this._products); }, addProduct : function(product){ this._products.push(product); this.notify(); }, loadProducts : function(){
ShopService.loadProducts().then(function(products){ this._products = products; this.notify();}.bind(this));
}});
Code
Abs
traç
ão
Abs
traç
ão
O Dispatcher delega as atualizações para todos os Stores
Abs
traç
ão
Mostrar custom elementvar shopStore = FooFlux. createStore({ id : 'shopStore', _products : [], getProducts : function(){
return _.cloneDeep(this._products); }, addProduct : function(product){ this._products.push(product); this.notify(); }, loadProducts : function(){
// ... }});
FooFlux.getDispatcher().register(function(actionName, data) { switch (actionName) { case 'addProduct': shopStore. addProduct(data); break; case 'loadProductList' : shopStore. loadProducts(); break; }});
Code
Abs
traç
ão
A Action expressa a intenção semanticamente e a passa para o Dispatcher
Abs
traç
ão
Mostrar custom elementFooFlux.getDispatcher().register(function(actionName, data) { switch (actionName) { case 'addProduct': shopStore. addProduct(data); break; case 'loadProductList' : shopStore. loadProducts(); break; }});
var shopActions = FooFlux.createActionCreator({ id: 'shopActions', addProduct : function(product){ // propagate to Store via Dispatcher FooFlux.getDispatcher().dispatch('addProduct', product); }, loadProductList : function(){
FooFlux.getDispatcher().dispatch('loadProductList' ); }});
Code
Abs
traç
ão
SimplificandoA
bstr
ação
Abs
traç
ão
Abs
traç
ão
Mostrar custom elementvar ProductListContainer = React. createClass({
getInitialState : function(){ return {products : []} },
onProductsChanged : function(products){ this.setState( {products : products}); if(this.props.onChanged){ this.props.onChanged(products) ; } },
componentDidMount : function(){ ShopService. loadProducts().then(this.onProductsChanged ); },
render: function () { return ( <ProductList products={this.state.products}/> ); }});
React Example- Anterior
Abs
traç
ão
Mostrar custom elementvar ProductListContainer = React. createClass({
getInitialState : function(){ return {products : ShopStore.getProducts()} },
onProductsChanged : function(){ this.setState( {products : ShopStore.getProducts() }); },
componentDidMount : function(){ ShopStore. addChangeListener (this.onProductsChanged ); ShopActions.loadProducts(); },
componentWillUnmount : function(){ ShopStore. removeChangeListener (this.onProductsChanged ); },
render: function () { return ( <ProductList products={this.state.products}></ProductList> ); }});
React Example - Com Flux
Abs
traç
ão
Simplifica o fluxo de dados
Escala com a complexidade
Separação de conceitos
Desacoplamento
Conc
lusã
o
R.I.P. 2-way-binding?
Conc
lusã
o
Não!
Conc
lusã
o
Não!
*Dentro* de um componente é viável e até necessário, mas deve ser utilizado com cautela.
Conc
lusã
o
Não!
Os frameworks modernos continuam a usar/suportar two-way-binding.
Hoje o conceito é bem entendido eexistem várias implementações
Conc
lusã
o
Facebook Flux https://facebook.github.io/flux/Alt.js http://alt.js.org/Fluxible http://fluxible.io/NanoFlux https://github.com/ohager/nanofluxetc pp
Variações de Flux original
Conc
lusã
o
NanoFluxhttps://github.com/ohager/nanoflux
Refluxhttps://github.com/reflux/refluxjs
Redux http://redux.js.org/“Predictable Application State Container”
- Único Store (unindo Dispatcher e Action Creator)
- Usar funcões (“Reducers”) para alteração de Status