Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
既存プロダクトのViewをReactに置き換える
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
boiyama
December 15, 2016
Programming
2.2k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
既存プロダクトのViewをReactに置き換える
【ヒカ☆ラボ】最新フロントエンドフレームワークを利用した開発事例!
https://atnd.org/events/83403
用の資料です
boiyama
December 15, 2016
More Decks by boiyama
See All by boiyama
Reproのビジネスサイドを支えるJS
boiyama
0
190
バックオフィスに行ったソフトウェアエンジニアの業務効率化事例
boiyama
1
280
2018年、IE6対応サイトを作る
boiyama
4
1k
ヤバいESLint/TSLintルール作っちゃったかもしれない
boiyama
0
1.5k
チームをCQRS
boiyama
1
1.6k
フロントエンドのサーバーレス SSR編
boiyama
0
720
Serverless for Front-end Server-Side Rendering
boiyama
1
130
Learning Elm in JS
boiyama
1
570
JSでElmを学ぶ
boiyama
0
110
Other Decks in Programming
See All in Programming
Vite+ Unified Toolchain for the Web
naokihaba
0
240
Lessons from Spec-Driven Development
simas
PRO
0
170
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
5
3.9k
ふつうのFeature Flag実践入門
irof
7
3.7k
A2UI という光を覗いてみる
satohjohn
1
120
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4k
The NotImplementedError Problem in Ruby
koic
1
700
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
230
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
210
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
320
Oxcを導入して開発体験が向上した話
yug1224
4
300
Modding RubyKaigi for Myself
yui_knk
0
910
Featured
See All Featured
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
390
Evolving SEO for Evolving Search Engines
ryanjones
0
210
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
AI: The stuff that nobody shows you
jnunemaker
PRO
8
700
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
560
GitHub's CSS Performance
jonrohan
1033
470k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
340
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
200
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
480
Navigating Weather and Climate Data
rabernat
0
220
Rebuilding a faster, lazier Slack
samanthasiow
85
9.5k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
180
Transcript
طଘϓϩμΫτͷViewΛ Reactʹஔ͖͑Δ Dec 15 2016 @boiyaa
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ϓϩϑΟʔϧ ▸ @boiyaa ▸ 33ࡀ ▸ ϑϧεέοϕΤϯδχΞ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ͢͜ͱɾ͞ͳ͍͜ͱ ▸ ͢͜ͱ ▸ طଘϓϩμΫτʹReactΛಋೖ͢Δ͜ͱʹͨ͠എܠ ▸ ࣮αϯϓϧ ▸ https://github.com/boiyaa/todomvc-backbone-react
▸ ͞ͳ͍͜ͱ ▸ πʔϧͱ͔ES6ͱ͔ͷৄ͍͠༰
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ࣮ݱࡏ ▸ View͚ͩஔ͖͑ΔͷΊ͍ͯ·͢ʢٕज़తෛ࠴తͳཧ ༝Ͱʣ ▸ ͜ͷεϥΠυͰɺViewΛReactʹஔ͖͑Α͏ͱࢼߦࡨޡ ͍ͯͨ࣌͠ͷ͓Λ͠·͢
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ৽ٕज़Λݕ౼ͨ͠എܠ ▸ 4લʹ࡞ΒΕͨۀγεςϜ ▸ ϑϩϯτΤϯυFWʹBackbone.jsΛ࠾༻ ▸ ػೳͷܧ͗͠Λ܁Γฦ͍ͯͬͨ݁͠ՌɺDOMૢ࡞ͷॲཧ͕ᷓΕ͔͑ͬͨ Backbone ViewʹͳΔ
▸ ͏গ͠εϚʔτʹUIΛ࡞ΕΔํ๏ʹม͑ΔͨΊɺjQueryʹґଘ͠ͳ͍React ͱAngular2͕ީิʹ্͕Δ ▸ Ͱ͖Εطଘࢿ࢈׆༻͍ͨ͠ͱ͍͏͜ͱͰɺUI·ΘΓͷΈΛReactʹஔ͖ ͑ΔํࣜͱɺAngular2Ͱ1͔Β࡞Γ͢ํࣜͷ̎௨Γݕ౼͢Δ͜ͱʹͳͬͨ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ࣌ͷݕূ༰ ▸ ̍൪ӈͷ߲͍͍ͬͨͳΜͩͱ͍͏ײ͡Ͱ͕͢ɺݱߦʹͦ͏͍͏ը໘͕͋Γɺ ສݸͷDOMͷඳըૢ࡞ʹ͕͔͔࣌ؒΔΑ͏ͩͱଞ߲͕ັྗతͰ࠾༻Ͱ ͖ͳ͍ͱ͍͏͜ͱͰ༻ҙ͞Ε߲ͨͰ͢ɻʢWhy?ʣ ▸ ݁ՌɺAngular2མબ͠ɺBackboneͷΈͷը໘ͱBackbone + Reactͷը໘Λ
͍͚͍ͯ͘ͱ͍͏͜ͱʹͳΓ·ͨ͠ ֶशίετ ੜ࢈ੑ อकੑ طଘࢿ࢈׆༻ ̍ສߦදૢ࡞ ύϑΥʔϚϯε Backbone ˕ ̋ ˚ ˕ ̋ Backbone + React ̋ ˕ ̋ ̋ ˚ Angular2 ˚ ˕ ̋ × ˚
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Reactʹ͍ͭͯ ▸ MV*Ͱ͍͏ViewͷΈఏڙ͢ΔϑϨʔϜϫʔΫ ▸ React͚ͩͳΒ֮͑Δ͜ͱগͳ͍Ͱ͢ ▸ React ComponentΫϥεΛܧঝ͠ɺHTML, CSS,
JSͷͻͱ͔ͨ·ΓΛఆٛͨ͠ίϯ ϙʔωϯτΛ࡞Δͷ͕جຊతͳ͍ํͰ͢ɻ ▸ ίϯϙʔωϯτɺJSXͱ͍͏จ๏ΛͬͯHTMLͷΑ͏ʹݺͼग़͠·͢ʢྫɿ <Example hoge=“fuga” />ʣ ▸ ίϯϙʔωϯτʹͨ͠propsɺίϯϙʔωϯτ͕࣋ͭstateʹೖΓɺͦΕ Βͷ͕ߋ৽͞ΕΔͱίϯϙʔωϯτ͕࠶ඳը͞Ε·͢ ▸ Πϕϯτॲཧλάଐੑʹઃఆ͠·͢ʢྫɿ<Example onClick={handleClick} />ʣ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Backboneʹ͍ͭͯ ▸ RESTful APIͱͷ࿈ܞΛγϯϓϧʹநԽɻେ͖̏ͭ͘ͷػೳΛ࣋ͪ·͢ ▸ Model: APIͷ୯Ϧιʔεͱಉظ ▸ Collection:
Modelͷू߹ͰɺAPIͷෳϦιʔεͱಉظ ▸ View: ඥͮ͘ModelCollectionͷσʔλΛDOMʹө͠ɺDOMͷϢʔβೖྗ ΛModelCollectionʹө
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ReactԽ Part.1 : ΊͪΌΊͪΌബ͘ReactΛ͏ ▸ Ұ൪؆୯ͳ͍ํͰ͢ɻ ؆୯ʹಋೖͰ͖·͕͢ɺ͜ͷ͍ํͰReact͍͍ͨਓ͍ͳ͍ͱ ࢥ͏ͷͰɺࢀߟఔʹհ͠·͢ ▸
ࢀߟURL ▸ https://facebook.github.io/react/docs/installation.html#using-a-cdn ▸ https://facebook.github.io/react/docs/react-without-es6.html ▸ https://facebook.github.io/react/docs/react-without-jsx.html ▸ ຊདྷReactɺYarn,npmͷύοέʔδϚωʔδϟɺwebpack,Browserifyͷόϯυϥɺ BabelͷίϯύΠϥΛซͤͯ׆༻͢Δ͜ͱΛਪ͍ͯ͠·͕͢ɺࠓճͦΕΒͷπʔϧ ΛΘͣ͏ํ๏Ͱ͢
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Α͋͘ΔBackboneϓϩδΣΫτͷྫ ▸ htmlʹςϯϓϨʔτΛॻ͍ͯɺ <script type="text/template" id="item-template"> <div class="view"> <input
class="toggle" type="checkbox" <%= completed ? 'checked' : '' %>> <label><%- title %></label> <button class="destroy"></button> </div> <input class="edit" value="<%- title %>"> </script>
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Α͋͘ΔBackboneϓϩδΣΫτͷྫ ▸ BackboneViewͰɺUnderscoreͱjQueryͰඳը͠·͢Ͷ template: _.template($('#item-template').html()), render: function () {
this.$el.html(this.template(this.model.toJSON())); },
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ htmlʹCDNͷReactΛه͠ɺ <script src="https://unpkg.com/react@15/dist/react.js"></ script> <script src="https://unpkg.com/react-dom@15/dist/react- dom.js"></script>
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ htmlͷςϯϓϨʔτΛফͯ͠ɺReact ComponentΛ࡞Γ·͢ var Item = React.createClass({ render:
function() { return React.createElement('div', null, React.createElement('div', {className: 'view'}, React.createElement('input', { className: ‘toggle', type: ‘checkbox', checked: this.props.completed }, null), React.createElement('label', null, this.props.title), React.createElement('button', {className: 'destroy'}, null) ), React.createElement('input', { className: ‘edit', defaultValue: this.props.title }, null) ); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ BackboneViewͷඳը͢Δͱ͜ΖΛॻ͖͑·͢ render: function () { ReactDOM.render( React.createElement(Item,
this.model.toJSON(), null), this.$el.get(0) ); },
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ <script type="text/template" id="item-template"> <div class="view"> <input class="toggle" type="checkbox" <%=
completed ? 'checked' : '' %>> <label><%- title %></label> <button class="destroy"></button> </div> <input class="edit" value="<%- title %>"> </script> var Item = React.createClass({ render: function() { return React.createElement('div', null, React.createElement('div', {className: 'view'}, React.createElement('input', { className: ‘toggle', type: ‘checkbox', checked: this.props.completed }, null), React.createElement('label', null, this.props.title), React.createElement('button', {className: 'destroy'}, null) ), React.createElement('input', { className: ‘edit', defaultValue: this.props.title }, null) ); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ template: _.template($('#item-template').html()), render: function () { this.$el.html(this.template(this.model.toJSON())); }, render:
function () { ReactDOM.render( React.createElement(Item, this.model.toJSON(), null), this.$el.get(0) ); },
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part.1 ·ͱΊ ▸ ͱͯݟͮΒͯ͘ݏͰ͢Ͷɻ ▸ ReactͬΆ͞ΛࣺͯΕɺಋೖࣗମ؆୯ʹͰ͖Δͱ͍͏ྫ Ͱͨ͠
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ReactԽ Part.2 : JSXͰBackbone TemplateΛஔ͖͑Δ ▸ ύοέʔδϚωʔδϟɺόϯυϥɺίϯύΠϥΛಋೖ͢Δ͜ͱʹͳΓ·͕͢ɺ ReactࣗମͰ֮ ͑Δ͜ͱগͳ͍͍ํͰ͢ɻ
πʔϧʹ׳Ε͍ͯͳ͚Εɺ࿅शʹͪΐ͏Ͳ͍͍͘Β͍ͷม ߋྔͰ͠ΐ͏ɻ ▸ ࢀߟURL ▸ https://nodejs.org/en/download/package-manager/ ▸ https://yarnpkg.com/en/docs/install#alternatives-tab ▸ https://facebook.github.io/react/docs/installation.html#installing-react ▸ https://webpack.js.org/guides/installation/ ▸ https://babeljs.io/docs/setup/#installation ▸ https://facebook.github.io/react/docs/introducing-jsx.html
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ඞཁͳͷΛΠϯετʔϧ͢Δ ▸ ύοέʔδϚωʔδϟYarnΛΠϯετʔϧ ▸ ύοέʔδϚωʔδϟͱ͍͑npmͰ͕͢ɺReactؔ࿈ͷυΩϡϝϯτͰyarnϕʔ εͰॻ͔Ε͍ͯΔ͜ͱ͕ଟ͍ͷͰࠓճͪ͜ΒΛ͍·͢ɻ ▸ ίϚϯυେମޓ͍ͯ͠ΔͷͰɺnpm͕͍͍ํదٓஔ͖͑ͯಡΜͰ͍ͩ͘͞ɻ ▸
npmίϚϯυରরදɿ https://yarnpkg.com/en/docs/migrating-from-npm ▸ YarnΛͬͯɺReactͱɺόϯυϥʹwebpackɺίϯύΠϥʹbabelΛΠϯετʔϧ yarn add react react-dom yarn add webpack babel-core babel-loader babel-preset-react --dev
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ React ComponentΛ࡞ͬͯΈ·͢ ▸ ҰݟHTMLʹݟ͑Δ͜ͷจ๏͕JSXͰ͢ɻ className, defaultValueগ͠HTMLͱ ҧ͏ଐੑ͕͋Γ·͢Ͷɻ
var Item = React.createClass({ render: function() { return ( <div> <div className="view"> <input className="toggle" type="checkbox" checked={this.props.checked} /> <label>{this.props.title}</label> <button className="destroy"></button> </div> <input className="edit" defaultValue={this.props.title} /> </div> ); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ BackboneViewͷඳը͢Δͱ͜ΖΛॻ͖͑ͯΈ·͢ render: function () { ReactDOM.render( <Item
title={this.model.get('title')} checked={this.model.get('completed')} />, this.$el.get(0) ); },
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ <script type="text/template" id="item-template"> <div class="view"> <input class="toggle" type="checkbox" <%=
completed ? 'checked' : '' %>> <label><%- title %></label> <button class="destroy"></button> </div> <input class="edit" value="<%- title %>"> </script> var Item = React.createClass({ render: function() { return ( <div> <div className="view"> <input className="toggle" type="checkbox" checked={this.props.checked} /> <label>{this.props.title}</label> <button className="destroy"></button> </div> <input className="edit" defaultValue={this.props.title} /> </div> ); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ template: _.template($('#item-template').html()), render: function () { this.$el.html(this.template(this.model.toJSON())); }, render:
function () { ReactDOM.render( <Item title={this.model.get('title')} checked={this.model.get('completed')} />, this.$el.get(0) ); },
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ ςϯϓϨʔτ෦ࣅͨΑ͏ʹهड़Ͱ͖ΔΑ͏ʹͳΓɺඳ ը෦͕ײతͳදݱʹͳΓ·ͨ͠Ͷ ▸ ͨͩ͠ɺ͔͜͜ΒϏϧυ͢Δ࡞ۀ͕ඞཁͰ͢
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ webpack.config.jsΛ࡞ΓɺϏϧυઃఆΛॻ͖·͢ module.exports = { entry: { 'components/Item.js':
'./js/components/Item.js', 'views/todo-view.js': './js/views/todo-view.js' }, output: { path: `${__dirname}/dist`, filename: '[name]' }, module: { loaders: [ { test: /\.js$/, loader: 'babel', query: { presets: ['react'] }
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ package.jsonʹϏϧυεΫϦϓτΛه͠·͢ "scripts": { "build": "webpack" },
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ Ϗϧυ͠·͠ΐ͏ ▸ ͜ΕͰdistʹϏϧυͨ͠jsϑΝΠϧ͕ੜ͞ΕΔͷͰɺ͜ΕΛhtmlʹಡΈ ࠐ·ͤ·͢ yarn run build
<script src="node_modules/react/dist/react.js"></script> <script src="node_modules/react-dom/dist/react-dom.js"></ script> <script src="dist/components/Item.js"></script> <script src="dist/views/todo-view.js"></script>
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ςϯϓϨʔτΛReactԽ͢Δ ▸ ϑΝΠϧ͕Ͱ͖ΔͨΊɺϖʔδؒͰͷςϯϓϨʔτͷڞ༗͕༰қʹ ▸ ͨͩɺςϯϓϨʔτϑΝΠϧΓग़͚ͩ͠Ͱ͋ΕɺUnderscore TemplateͰJSTίϯύΠϥΛ࣮͑ݱͰ͖·͢ɻ ▸ ͦΕ͚ͩͩͱ͍ͨͨ͠ϝϦοτʹͳΓ·ͤΜͶ ▸
JSXͷ͞Βʹ͍͍ͱ͜ΖɺJSXͰReact ComponentΛݺͼग़͢͜ͱ ͕Ͱ͖ΔͷͰɺΑΓݟ͘͢ίϯϙʔωϯτͷೖΕࢠΛදݱͰ͖Δͱ ͜ΖͰ͢
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Underscore Templateͷ߹ ▸ ཁૉʹࢠཁૉΛՃ͢ΔͳΒɺView͔ΒViewΛݺͼग़ͯ͠ɺ DOMʹૠೖ͢ΔॲཧΛॻ͘͜ͱʹͳΓ·͢ ▸ html <script type="text/template"
id="parent"> <div class="parent"></div> </script> <script type="text/template" id="child"> <div class="child"><%- text %></div> </script>
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Underscore Templateͷ߹ ▸ js var ChildView = Backbone.View.extend({ template:
_.template($('#child').html()), render: function () { this.$el.html(this.template(this.model.toJSON())); } }); var ParentView = Backbone.View.extend({ template: _.template($('#parent').html()), render: function () { this.$el.html(this.template()); var parent = this.$el.find('.parent'); this.collection.each(function (model) { var child = new ChildView({model: model}); parent.append(child.$el); }); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Reactͷ߹ ▸ ίϯϙʔωϯτ͔ΒίϯϙʔωϯτΛݺͼग़ͤ·͢ var Parent = React.createClass({ render: function()
{ var children = []; this.props.collection.each(function (model) { children.push(<Child model={model}>); }); return <div className="parent">{children}</div>; } }); var Child = React.createClass({ render: function() { return <div className="child">{this.props.text}</div>; } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Reactͷ߹ ▸ ͳͷͰView1ͭʹͳΓ·͢ var ParentView = Backbone.View.extend({ render: function
() { ReactDOM.render( <Item collection={this.collection} />, this.$el.get(0) ); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part.2 ·ͱΊ ▸ ͜ͷΑ͏ʹγϯϓϧʹهड़Ͱ͖ɺؾܰʹڞ௨UI෦Λͯ͠͠·͑·͢ɻ Child͕ඳըͷΈͰ͍͍߹ɺ͜ͷख๏ͰऔΓೖΕΔͷ͋Γͩͱࢥ͍·͢ɻ ▸ ͔͠͠ͳ͕Βɺ Childʹੜ࣌Ϣʔβೖྗ࣌ͷΠϕϯτॲཧΛ࣋ͨͤͯɺͦΕڞ௨Խ͍ͨ͠ ͱ͍͏߹ɺ
React ComponentͰͦ͏͍ͬͨࣄॻ͚·͕͢ɺͷʹΑͬͯBackbone View ʹॻ͍ͯ͋ͬͨΓReact Componentʹॻ͍ͯ͋ͬͨΓ͢ΔͱɺՄಡੑอकੑ ΛԼ͛ͯ͠·͏ͷͰɺ ݁ہChildͷBackbone ViewΛ࡞ͬͯParentView͔Βݺͼग़͢͜ͱʹͳΓ·͢ɻ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ReactԽ Part.3 : Backbone ViewΛReact Componentʹஔ͖͑Δ ▸ React ComponentͷػೳͰBackbone
ViewͰ͍ͬͯΔ͜ͱΛҠ২͠·͢ɻ ▸ มߋྔ݁ߏ͋ΓɺES2015+Λಋೖ͠JSͷॻ͖ํ͕݁ߏมΘΓ·͕͢ɺ Backboneʹͳ͍ViewͷՄಡੑɾอकੑ্ͷͨΊͷ༷ʑͳϝϦοτΛڗ डͰ͖·͢ɻ ▸ ࢀߟURL ▸ https://facebook.github.io/react/docs/components-and-props.html ▸ https://facebook.github.io/react/docs/handling-events.html
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Α͋͘ΔBackbone View var View = Backbone.View.extend({ tagName: 'li', //
ユーザ入力イベントとハンドラの紐付け events: { 'click .toggle': 'toggleCompleted' }, // モデル変更イベントとハンドラの紐付け initialize: function () { this.listenTo(this.model, 'change', this.render); }, render: function () { this.$el.html(this.template(this.model.toJSON())); }, toggleCompleted: function () { this.model.toggle(); } });
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ React ComponentԽ // 依存ライブラリの参照はHTMLではなくjsに書く import Item, {Component} from 'react';
// classが使える class Todo extends Component { // 描画後イベント componentDidMount() { // モデル変更イベントとハンドラの紐付け this.props.model.on('change', this.handleChangeModel); } handleChangeModel() { // 描画実行 this.forceUpdate(); } handleClickToggle() { this.props.model.toggle(); } 〜つづく〜
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ React ComponentԽ 〜つづき〜 render() { const title = this.props.model.get('title');
const completed = this.props.model.get('completed'); // ユーザ入力イベントとハンドラの紐付け return ( <li> <div className="view"> <input className="toggle" type="checkbox" checked={completed} onClick={this.handleClickToggle} /> <label>{title}</label> </div> </li> ); } }
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ React ComponentԽ ▸ BackboneɺϚʔΫΞοϓͱJSΛ͠·͕͢ɺReactɺ݁߹͠·͢ɻ HTMLίʔσΟϯά͔͠Ͱ͖ͳ͍ਓͱɺϓϩάϥϚͷۀͰ͍ͬͯΔνʔϜͩͱෆ͖ʁ ▸ খ͘͞࡞ΒΕͨίϯϙʔωϯτɺ ΠϕϯτͷྲྀΕ͕ಡΈ͘͢ɺίʔυ͕ࢄ͍ͯ͠ͳ͍ͷͰɺ ࠶ར༻࣌ʹؾʹ͔͚Δ෦ݮΓ·͢ɻ
▸ ·ͨ෦Ͱఆٛ͞ΕͨϝιουCSSΫϥεӅṭ͞Εɺ ֎͔Βࢀর͢Δ͜ͱ͕Ͱ͖ͳ͍ͷͰɺ໊લͷڝ߹ͰࠔΔ͜ͱ͕ͳ͘ͳΔɺ ϝϦοτ͕͋Γ·͢ɻ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ React ComponentԽ ▸ htmlʹࢀরΛه͢Δࡍɺ webpackʹΑͬͯɺimportઌͷϑΝΠϧΛશͯΤϯτϦʔϑΝ Πϧʹ݁߹͞Ε͍ͯΔͷͰɺಡΈࠐΉͷ1ͭͰΑ͘ͳΓ·͢ <script src="dist/views/app-view.js"></script>
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part.3 ·ͱΊ ▸ Backbone ViewͰΓʹ͍͘ίϯϙʔωϯτࢦΛ༰қ ʹͰ͖·ͨ͠ ▸ UIͷΈίϯϙʔωϯτͷೖΕࢠ͚ͩͰͳ͘ɺ ςϯϓϨʔτ͚ͩͷReactԽͷ՝ͱͳΔɺػೳͷ͋Δίϯ
ϙʔωϯτͷڞ༗ɺ Backbone View͝ͱReact Componentʹஔ͖͑Δ͜ͱͰ ࣮ݱͰ͖·ͨ͠
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ReactԽ Part.4 : ComponentΛׂͰׂ͠ɺ࠶ར༻ੑΛߴΊΔ ▸ Part3ͰɺϩδοΫͷ͋ΔComponent෦Ͱঢ়ଶૢ࡞Λߦ͍ͬͯΔ ͨΊɺ ෦༻ͷঢ়ଶϓϩύςΟstateΛ༻͍ͯ͠·͢ɻ ▸
͔͠͠ͳ͕ΒɺComponentεςʔτϨεʹ࡞ΒΕ͍ͯΔํ͕ɺ Մಡੑɾ࠶ར༻ੑɾςελϏϦςΟ্͕͠·͢
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Componentͷׂ ▸ ReactΛ༻͢ΔFWͷFlux UtilsReduxͰɺ ComponentΛ2ׂͭͰׂ͢Δ͜ͱΛਪ͍ͯ͠·͢ɻ ▸ 1ͭɺ͞ΕΔpropsʹԠͯ͡UIΛඳը͢ΔεςʔτϨείϯϙʔωϯτ ͏1ͭɺσʔλͱViewΛૢ࡞͢Δίϯϙʔωϯτ
લऀViews·ͨPresentational Componentsɺ ޙऀContainers·ͨContainer ComponentsͱݺΕ·͢ ▸ ࢀߟURL ▸ https://facebook.github.io/flux/docs/flux-utils.html#best-practices ▸ http://redux.js.org/docs/basics/UsageWithReact.html#presentational-and- container-components
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part3ͷComponentΛViewͱContainerʹׂ͢Δ ▸ View ▸ propsΛඳը͢Δ͚ͩ ͳͷͰFunctional Componentʹ͠·͢ ▸ https://
facebook.github.io/ react/docs/ components-and- props.html#functional- and-class-components const Item = (props) => { // 状態は外から渡される const {title, checkedToggle} = props; const handleClickToggle = () => { // 外から渡されたハンドラにそのまま返す props.onClickToggle(); } return ( <li> <div className="view"> <input className="toggle" type="checkbox" checked={checkedToggle} onClick={handleClickToggle} /> <label>{title}</label> </div> </li> ); }
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part3ͷComponentΛViewͱContainerʹׂ͢Δ ▸ Container class ItemContainer extends Component { componentDidMount()
{ this.props.model.on('change', this.handleChangeModel); } handleChangeModel() { this.forceUpdate(); } handleClickToggle() { this.state.model.toggle(); } render() { const title = this.props.model.get('title'); const completed = this.props.model.get('completed'); // Itemの状態はこちらで管理する return ( <Item title={title} checkedToggle={completed} onClickToggle={handleClickToggle} /> ); } }
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part.4 ·ͱΊ ▸ σʔλͷΓͱΓͱɺUIͷදݱ͕ผΕͨ͜ͱͰɺ ͞ΒʹUIͷ࠶ར༻ੑ্͕ͨ͠ͱࢥ͍·͢ɻ ▸ ྫ͑ɺDate PickerͷΑ͏ͳϢʔβೖྗUIɺ ೖྗʹΑͬͯͲ͏ॲཧ͢Δ͔ɺ͏ॴͰܾΊ͍ͨͷͳͷ
Ͱɺ͜ͷϓϥΫςΟε͕༗ޮʹಇ͖·͢ɻ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ReactԽ Part.5 : σʔλϑϩʔʹFluxΛऔΓೖΕΔ ▸ FluxFacebook͕ఏএ͢Δ୯ํσʔλϑϩʔΞʔΩςΫνϟ ▸ Model-ViewͰModel͕σʔλͱσʔλʹର͢ΔཁٻΛ͍࣋ͬͯ·͕͢ɺ FluxͰɺσʔλ(Store)ͱσʔλʹର͢Δཁٻ(Action)Λ͠·͢
▸ Reactɺ͜ͷΈͷதͰViewʹΘΕΔ͜ͱΛਪ͍ͯ͠·͢
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ BackboneʹFluxͷ֓೦ΛऔΓೖΕΔʹ ▸ ͷൣғΛ୲͍ͬͯΔCollectionModelΛׂ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part.5 ·ͱΊ ▸ ݱঢ়ViewModelʹϩδοΫ͕ࢄΒ͔͍ͬͯΔ͕ɺ ActionΛऔΓೖΕͨ͜ͱͰɺߋ৽ͱऔಘΛ͢Δ͜ͱ͕Ͱ͖ɺ ϩδοΫͷཧͱංେԽΛ͑ΒΕͦ͏Ͱͨ͠ ▸ ͔͠͠ɺDispatcherͱ͔ɺViewͱModelΛDispatcherͰඥ͚Δ ෦ͱ͔ɺಠ࣮ࣗ͢Δͱ͜Ζ͕৭ʑ͋ͬͯɺ݁ہBackbone
Ϣʔβʹͱֶͬͯशίετ͕͔͔ͬͯ͠·͏ײ͡Ͱ͢ ▸ ͰɺFLUXɺCQRS + Event Sourcingύλʔϯͱ͍ͬͨҰํ ͷσʔλϑϩʔτϨϯυͳͷͰੋඇ͓͓͖͍͑ͯͨ͞Ͱ͢Ͷɻ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ࣮͜ͷࠒʹ ▸ ͳΜ͔ٕज़తෛ࠴ଟա͗ͯɺReactʹஔ͖͑ʹ͍͘ॴ͕ ͋Γ͗͢Δͱ͍͏ݱ࣮ʹ໘͍ͯ͠·ͨ͠ɻ ▸ ݁ہϓϩδΣΫτෛ࠴ฦࡁͱ৽ن։ൃʹ͠·ͨ͠ɻ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ ReactԽ Part.6 : BackboneΊΔ ▸ ৽ن։ൃϓϩδΣΫτ͕࢝·ΓɺτϨϯυͷReduxͱɺ Facebook͕ϝϯςφϯε͢ΔFlux UtilsͰൺֱ͢Δ͜ͱʹͳΓ ·ͨ͠ɻ
▸ ͜ͷ2ͭͷେ͖ͳҧ͍ɺReduxʹ1ͭͷΦϒδΣΫτʹΞϓ ϦέʔγϣϯશମͷεςʔτΛ·ͱΊΔݪଇ͕͋Δɺͱ͍͏ͱ ͜ΖͰ͢ɻ ▸ ElmͷӨڹΛड͚ͨReduxɺؔܕϓϩάϥϛϯάͷ׆༻ʹ Αͬͯอकੑͷߴ͍ίʔυΛॻ͚ΔͷͰ͍͍ͱࢥ͍·ͨ͠ɻ
طଘϓϩμΫτͷViewΛReactʹஔ͖͑Δ Part.6 ·ͱΊ ▸ ͔ͳΓࡉ͔͍ίʔσΟϯάνΣοΫઃఆͰ͋Δeslint-config- airbnbΛซ༻͢Δͱ͍͍ͱࢥ͍·͢ɻ ▸ FacebookJS੩తܕνΣοΧʔͷFlowซͤͯಋೖ͠ɺ JSʹڧ͍ܕ͚ͱnullඇڐ༰Λ͚ͭΔͱΑΓ҆৺Ͱ͠ΐ͏ɻ
THAT'S IT. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠