SED 〜SIROK技術勉強会 #3「フロントエンドMVCとFlux(仮)」〜 https://atnd.org/events/68943
ϑϩϯτΤϯυMVCͱFluxSED | SIROKٕज़ษڧձ2015/08/13
View Slide
About Me• @sangotaro• Frontend Engineer• SIROK: 2ϲ݄
FluxΓ͍ͨͷͰɺFluxڭ͢Δ!
·ͣMVCͷ෮श
MVC
MVC• GUIΞϓϦΛ࣮͢ΔͨΊͷσβΠϯύλʔϯ• αʔόʔαΠυMVCੜܥ• ͍ΖΜͳྲྀ͕͋ΔͷͰݴٴ͠ͳ͍
ModelσʔλͱϏδωεϩδοΫΛ୲ɻσʔλͷมߋΛViewʹ௨͢ΔɻViewσʔλΛදࣔ͢Δɻ௨ৗ֊ߏΛʹͳΔɻControllerϢʔβ͔ΒͷೖྗΛϞσϧʹ͑ΔɻҾ༻ݩ: https://ja.wikipedia.org/wiki/Model_View_Controller
JSϥΠϒϥϦͷ༗໊Ͳ͜Ζ• Backbone.js• AngularJS• Knockout.js• Ember.jsͦΕͧΕݫີʹMVCͰͳ͍ͷͰɺ૯শͱͯ͠MVW or MV*ͱݺΕΔɻ
Backbone.jsͰ• Backbone.View: ControllerɺView• Backbone.Model: Model
GUIΞϓϦͷઃܭ
GUIΞϓϦઃܭͷϙΠϯτෳࡶͳ"ঢ়ଶ"ʹͲ͏ཱ͔ͪ͏͔
ঢ়ଶ(State)???• ঢ়ଶ = UIͷঢ়ଶ• σʔλͦͷͷͰͳ͍❌• ͲͪΒJSONͷΑ͏ͳσʔλߏͰදݱͰ͖Δ
σʔλͱঢ়ଶex. ࡏݿ͕0ͷͱ͖ɺߪೖϘλϯ͕ԡͤͳ͍σʔλ => ࡏݿ0ɹঢ়ଶ => Ϙλϯ͕ແޮlet data = {inventory: 0}let state = {buyButton: 'disable'}
͠͞• ཧ͢Δঢ়ଶ͕ଟ͗͢Δ!• Ͳ͜Ͱঢ়ଶΛཧ͢Δ͔"• ͩΕ͕ঢ়ଶΛมߋ͢Δ͔#
Backbone.jsͰͬͯΈΔͱ
ެࣜͷਤҾ༻ݩ: http://backbonejs.org/
γϯϓϧͰΑͦ͞͏?
࣮ࡍෳࡶͩ͠ɺܾΊΔ͜ͱଟ͍!
େྔͷViewɺେྔͷModel͕૬ޓʹؔ࿈͢Δ• Model-VIewؒͷํσʔλϑϩʔ• ViewɺࢠView• ෳࡶ͕രൃ
UIͷঢ়ଶͲ͜ʹ͋Δͷ͔• Model or View(View or ࢠView)• ͦͦҙࣝͯ͠ঢ়ଶΛཧ͍ͯ͠Δ͔?• Model͕ͨͩͷσʔλModelʹͳͬͯͳ͍͔?• ViewͰෳࡶͳσʔλॲཧΛ͍ͯ͠ͳ͍͔ʁ
ͱֶ͍͑ͼ͋Δ
Backbone.js͕ڭ͑ͯ͘Εͨ͜ͱ
Viewͷ෦Խ• ࠶ར༻ՄೳͳView• ࠷ۙྲྀߦΓͷίϯϙʔωϯτࢦ• React• Angular• Web Components
Φϒβʔόʔύλʔϯ• Model͕มߋ͞ΕͨΒΠϕϯτൃՐ• ViewModelͷΠϕϯτࢹҾ༻ݩ: http://backbonejs.org/
Flux
Fluxͱ• Facebook͕ఏএͨ͠GUIΞϓϦͷΞʔΩςΫνϟ• ϥΠϒϥϦͰͳ͍• ࣮͕ཚཱ• Unidirectional data flow (୯ํσʔλϑϩʔ)• ΦϒβʔόʔύλʔϯͰ࣮ݱ
Fluxͷొਓ• Action• Dispatcher• Store• View
༗໊ͳਤҾ༻ݩ: https://facebook.github.io/flux/docs/overview.html#content
༗໊ͳਤ2Ҿ༻ݩ: https://github.com/facebook/flux/tree/master/examples/flux-todomvc/
ߏྫ(TODOΛ࡞Δ͚ͩͷΞϓϦ)src├── actions│ └── todo-action-creators.js├── app-constants.js├── app-dispatcher.js├── app.js├── stores| └── todo-store.js└── views├── todo-controller-view.react.js└── todo-item.react.js
Action & Action CreatorFluxͷσʔλϑϩʔͷ։࢝!ActionλΠϓͱσʔλΛͭΦϒδΣΫτ(like Πϕϯτ)Action CreatorActionΛੜ͢Δϔϧύʔؔ(or ϝιου)
// todo-action-creators.jsimport AppDispatcher from '../app-dispatcher';import AppConstants = from '../app-constants';var TodoActionCreators = {create: function(text) {AppDispatcher.dispatch({actionType: AppConstants.TODO_CREATE, // typetext: text // data});}}export default TodoActionCreators;
Dispatcher• άϩʔόϧͳEventEmitterΈ͍ͨͳͷ• ActionΛStoreʹಧ͚Δ(Φϒβʔόʔύλʔϯ)// ActionΛىಈ(Pub) like EventEmitter#emitAppDispatcher.dispatch(action);// ίʔϧόοΫͷొ(Sub) like EventEmitter#onAppDispatcher.registor(callback);
Store• σʔλͱঢ়ଶΛཧ(ঢ়ଶཧϩδοΫ͋Δ)• ActionͰ͔͠มߋͰ͖ͳ͍(No Setters, only gettes)• DispatcherʹίʔϧόοΫΛొ͢Δ
// todo-store.jslet _todos = {}; // private data// setterfunction create(text) {let id = (+new Date()).toString();_todos[id] = {id: id,text: text};}class TodoStore extend EventEmitter {constructor() {// TODO: Register dispatcher callback}// gettergetAll() {return _todos;}emitChange() {this.emit('change');}}export default new TodoStore;
// Register dispatcher callbackAppDispatcher.register(action => {switch(action.actionType) {case AppConstants.TODO_CREATE:let text = action.text.trim();if (text !== '') {create(text);this.emitChange(); // Emit change event}break;default:// no op}});
View• ex. React componets• Storeͷ"ঢ়ଶ"มԽͷΈΛࢹ• Action CreatorΛίʔϧ• େ͖͚ͯ͘2छ• Controller View• View
Controller View & ViewController View• ϧʔτ(ʹ͍ۙ)View• StoreͷมԽΛࢹ• ࣗͱࢠViewΛϨϯμϦϯάView• ྲྀΕ͖ͯͨσʔλΛݩʹϨϯμϦϯά
ͬ͘͟Γ·ͱΊΔͱ
ActionΛىʹσʔλ͕Ұप͢ΔҎ্
MVCͱͲ͕͜ҧ͏?
MVCͱͷҧ͍• ొਓͦΕͧΕͷׂ͕໌֬• Unidirectional data flow
Viewͷσʔλϑϩʔ• View͔ΒࢠViewͷҰํ௨ߦ• ٯͰ͖Εආ͚Δ• ࢠ͔ΒͷόέπϦϨʔ͠ͳ͍• ActionΛੜ͢Δ͖
ঢ়ଶStore͕ͭ• Viewࣗঢ়ଶΛมߋ͠ͳ͍• Storeʹ͋Δঢ়ଶread-only• ViewActionੜ͢Δ͚ͩ
StoreͱModelͷҧ͍• StoreModelΑΓׂ͕໌֬• (σʔλ͚ͩͰͳ͘)ঢ়ଶͭ• ActionͰ͔͠มߋͰ͖ͳ͍
࣮͕γϯϓϧ• Pub/Sub͕໌֬ʹ͍ͯ͠Δ
ͿͬͪΌ͚ΦϨΦϨMVCͰ?
FacebookͷΦϨΦϨMVCઆ• ͨͿΜͦ͏• ৽͍͠ొਓΛఆٛͯ͠໌֬ͳׂΛ༩͑ͨ• Fluxͱ͍͏MV*ܥͱࢥΘΕͳ͍ωʔϛϯά
࠷ۙͷFlux
facebook/fluxͷෆຬ• ͱ͖ͬͭʹ͍͘• DispacherͨͩͷEventEmitterͰ?• Action (Creator)ͨͩͷؔͰ?• γϯάϧτϯ• αʔόʔαΠυͰࠔΔ• ςετ͠ʹ͍͘
ͦΕͰUnidirectional data flow͍͍ΑͶ
Flux࣮• Flux Comparison• URL: https://github.com/voronianski/flux-comparison• ελʔ্Ґ⭐• Redux• Reflux• Alt
·ͱΊ
Flux࠷ߴ͔ͩΒΖ͏React͡Όͳͯ͘Ͱ͖ΔΑ
࣍ճ