Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Real World Virtual DOM

Real World Virtual DOM

React, Flux, Isormorphic そして現実

Koutarou Chikuba

February 16, 2015
Tweet

More Decks by Koutarou Chikuba

Other Decks in Technology

Transcript

  1. Virtual DOM ʹ͍ͭͯͷ׆ಈ ☞ VirtualDOM Advent Calendar 2014 - Qiita

    ͷओ࠵ ☞ ͋ͳ͕ͨReactΛ࢖͏΂͖ཧ༝ ☞ ͳͥԾ૝DOMͱ͍͏֓೦͕ԶୡͷࠢΛ਒͑ͤ͞Δ ͷ͔ - Qiita ☞ #13 Virtual DOM | mozaic.fm ͷήετ
  2. ࠓ೔ͷςʔϚ Real World Virtual DOM ☞ ୈҰষ: Kobito on AtomShell

    ☞ ୈೋষ: Arda - MetaFlux Framework ☞ ୈࡾষ: Isormorphicͷ࣮ફ ☞ ࠷ޙʹ: Virtual DOM ΛͱΓ·͘ݱ࣮
  3. ։ൃաఔ ☞ اը / ϓϩτ 10݄ޙ൒ ~ ☞ ઃܭ -

    11݄ ~ ☞ ࣮૷ - 12݄~ ☞ όάચ͍ग़͠ͱϦϑΝΫλ(͍·͜͜) ΤϯδχΞ1ਓ(mizchi) 1݄͔ΒϚʔΫΞοϓ1ਓ
  4. react-jade ͷྫ .container h1(onClick=onClickTitle)= This is title ↓ React.createElement('div', {className:

    'container'}, [ React.createElement('h1', {onClick: onClickTitle}, 'This is title') ]) // ϔομলུ ͍ΘΏΔhamlܥςϯϓϨʔτ
  5. ։ൃݴޠ ☞ UI૚: React Component / Dispatcher ☞ CoffeeScriptͰߴ଎ʹTry &

    Error Λճ͢ ☞ ςϯϓϨʔτ͸react-jade ☞ Store૚ / Domain૚ ☞ TypeScript ͷ common.jsϞʔυ ☞ CoffeeScript ʹ require ͞ΕΔ(ٯ͸ͳ͍)
  6. ཚཱ͢Δ Flux ࣮૷ ☞ Fluxxor ☞ Reflux ☞ Alt ☞

    Fluxible ☞ Facebook's flux ☞ Deloerean ☞ etc...
  7. Arda ☞ mizchi/arda - Github ☞ ݩʑ͸ Kobito on Atom

    Shell ͷঢ়ଶ؅ཧͱը໘ભ ҠΛந৅Խͨ͠΋ͷ ☞ ͦͦ͜͜ςετॻ͍ͯɺ͍ͩͿυοάϑʔσΟϯ ά͍ͯ͠ΔͷͰ࣮༻ʹ଱͑͏Δ͸ͣ
  8. Context ͷσʔλϑϩʔ ➀ Router ͔Βॳظೖྗ(Props)Λड͚ͯॳظԽ͞ΕΔ ➁ Props͔ΒॳظState(Context಺ঢ়ଶ)Λ࡞Δ ➂ Props ͱ

    State ͔ΒɺComponentʹ౉͢ϓϩύς Ο(ComponentProps)Λੜ੒ ➃ Component ʹ౉͢ ➄ ঢ়ଶ͕ߋ৽͞ΕͨΒ3ʹ໭Δ
  9. Arda.Router ☞ pushContext ☞ popContext ☞ replaceContext ☞ APIͰ࡯ͯ͠ ☞

    Contextͷੜ੒ͱഁغΛ୲౰(SPA͸ͦ͜Β΁Μݫ͠ ͍)
  10. ΫϦοΫͰ਺͕૿͑Δαϯϓϧ class Clicker extends Arda.Component render: -> React.createElement 'button', {onClick:

    @onClick.bind(@)}, @props.cnt onClick: -> @dispatch 'clicker:++' class ClickerContext extends Arda.Context @component: Clicker initState: (props) -> cnt: 0 expandComponentProps: (props, state) -> cnt: state.cnt delegate: (subscribe) -> super subscribe 'clicker:++', => @update((s) => cnt: s.cnt+1) router = new Arda.Router(Arda.DefaultLayout, document.body) router.pushContext(ClickerContext, {})
  11. ΫϦοΫͰ਺͕૿͑Δαϯϓϧ class Clicker extends Arda.Component render: -> React.createElement 'button', {onClick:

    @onClick.bind(@)}, @props.cnt onClick: -> @dispatch 'clicker:++' #<= EventEmitter΁ൃՐ class ClickerContext extends Arda.Context @component: Clicker initState: (props) -> cnt: 0 expandComponentProps: (props, state) -> cnt: state.cnt delegate: (subscribe) -> super subscribe 'clicker:++', => #<= EventEmitterͷEventड৴ @update((s) => cnt: s.cnt+1) router = new Arda.Router(Arda.DefaultLayout, document.body) router.pushContext(ClickerContext, {}) Event ͸Ұํ௨ߦ
  12. ΫϦοΫͰ਺͕૿͑Δαϯϓϧ class Clicker extends Arda.Component render: -> React.createElement 'button', {onClick:

    @onClick.bind(@)}, @props.cnt onClick: -> @dispatch 'clicker:++' class ClickerContext extends Arda.Context @component: Clicker initState: (props) -> cnt: 0 #<= ॳظঢ়ଶ expandComponentProps: (props, state) -> cnt: state.cnt #<= ComponentͷProps delegate: (subscribe) -> super subscribe 'clicker:++', => @update((s) => cnt: s.cnt+1) #<= ঢ়ଶͷߋ৽ router = new Arda.Router(Arda.DefaultLayout, document.body) router.pushContext(ClickerContext, {}) Mutable ͳͷ͸ State ͚ͩ
  13. Context Λ TypeScript Ͱهड़͢Δ ͱԿ͕خ͍͠ʁ ☞ ܕʹΑͬͯ࢓༷͕໌֬ʹͳΔ ☞ Props ͸ը໘Λ࠶ߏங͢Δͷʹඞཁͳ৘ใ

    ☞ State ͸ͦͷը໘ͷதͰมԽ͢Δঢ়ଶ ☞ ComponentProps ͸ ࣮ࡍʹComponent ʹ౉͞Ε Δ΋ͷ
  14. ͨͱ͑͹ ☞ Stateͱͯ͠Կ͔ͷ id ͚ͩ࣋ͬͯ DB΍ωοτϫʔ ΫΛୟ͘ͱɺ݁Ռʹ࠶ݱੑ͕ͳ͘ State ͱͯ࣋͠ ͪͨ͘ͳ͍

    buildTimelineByGroupId(state.selectedGroupId).then((items) = { this.render(items); // ͜͜Λ࣋ͪͨ͘ͳ͍ });
  15. ࠶ݱՄೳͳϏϡʔ ☞ ComponentProps͕ಉ͡ͳΒඞͣಉ͡ϏϡʔΛঢ় ଶΛ࠶ݱͰ͖Δ(ͱ͢Δ) ☞ Component ͱ Props ͷ૊Έ߹Θͤͷ URL΁ͷγ

    ϦΞϥΠζ/σγϦΞϥΠζ Λ࣮૷͢Ε͹ Browser Hisotry ʹରԠՄೳ ☞ Agnosticʹ͍ͨ͠ͷͰArdaͰ͸ϒϥ΢βώετϦ ʔΛؔ஌͠ͳ͍
  16. Kobito on Atom Shell Ͱͷ Arda ☞ Context Λ TypeScript

    ͰܕͰอޢ͢Δɻ ☞ Component ͸ CoffeeScript Ͱࡶʹॻ͍ͯ Event Λ dispatch ͢Δ ☞ Eventͷߪಡଆ͸TypeScript Ͱॻ͍͍ͯΔ͕ɺड ͚औΔҾ਺ʹ͍ͭͯ͸͓໿ଋఔ౓
  17. Arda with TypeScript interface Props {firstName: string; lastName: string;} interface

    State {age: number;} interface ComponentProps {greeting: string;} class MyContext extends Arda.Context<Props, State, ComponentProps> { initState(props){ return new Promise<State>(done => { setTimeout(done({age:10}), 1000) }) } expandComponentProps(props, state) { return {greeting: 'Hello, '+props.firstName+', '+state.age+' years old'} } } # தུ router.pushContext(MyContext, {firstName: 'Jonh', lastName: 'Doe'})
  18. Qiita ͱ Atom Shell ಛ༗ͷࣄ৘ ☞ node ͷ global ͱ

    ϒϥ΢βͷ window ͕ڞଘ͢Δ ಛघͳ؀ڥ ☞ ੒Ռ෺͸͍ͣΕQiita΁࣋ͪࠐΈ͍ͨ ͱ͍͏Θ͚ͰKobito on Atom Shell Ͱ͸ Isomorphic Λڧ͘ҙࣝͯ͠ઃܭͨ͠
  19. mochaͰͷ࣮ࡍͷίʔυͷҰ෦ schema.databases[0].type = 'memoryDb' global.stubDatabases = -> # helper beforeEach

    -> initDatabasesBySchema(schema).then ([db]) -> global.db = new Repository.Database(db) global.Item = db.getCollection('items') global.Team = db.getCollection('teams') afterEach -> delete global.db delete global.Item delete global.Team
  20. renderToString(...) var Component = React.createClass({ render: function(){return React.createElement('div', {}, 'this

    is title');} }); var html = React.renderToString(React.createFactory(Component)()); assert.ok(html.indexOf('this is title') > -1); componentWillMount ·Ͱݺ͹ΕΔͷ͕ϙΠϯτ (componentDidMount͸ݺ͹Εͳ͍)
  21. JSDOM jsdom = require('jsdom').jsdom; global.document = jsdom('<html><body></body></html>'); global.window = document.parentWindow;

    global.navigator = window.navigator; React = require('react/addons'); var el = React.createElement('div'); component = React.addons.TestUtils.renderIntoDocument(el) αʔόʔ(node)ͰΫϦοΫΠϕϯτൃՐ΋ςετͰ͖ Δɻ ࢀߟ: JSDOMͱReact.addons.TestUtilsͰReactΛϔου Ϩεʹςετ͢Δ - Qiita
  22. Kobitoͷ Isomorphic ͷ࣮ફ ☞ src/(.ts, .jade, .coffee) Λ૬ରύεΛҡ࣋ͨ͠··ί ϯύΠϧ͠ lib/(**.js)΁

    ☞ browserifyͰ lib/index.js Λ શ෦ೖΓ (node_modulesҎԼͷґଘؚΉ)ͷ bundle.js ͱ͠ ͯϏϧυ (gulpͰ֦ுࢠ͝ͱʹ؂ࢹͯࠩ͠෼Ϗϧυ)
  23. src/ - main.coffee - foo.ts - template.jade lib/ - main.js

    - foo.js - template.js public/ - bundle.js # lib node_modules ͷґଘશ෦ೖΓ - index.html node_modules/ - ... test/ - main-test.coffee
  24. ׬