Slide 1

Slide 1 text

(FU4UBSUFE3FBDUKT !LPCB WରԠ

Slide 2

Slide 2 text

facebook.github.io/react/

Slide 3

Slide 3 text

3FBDUKT W w +6455)&6* w .7$Ͱ͍͏ͱ͜Ζͷ7 㱠.7$'SBNFXPSL w 7*356"-%0. w Ծ૝ͷ%0.Λ͍࣋ͬͯͯɺࠩ෼͚ͩΛ࣮ࡍͷ%0.ʹ൓ө͢ΔͷͰߴ଎ w %"5"'-08 w XBZσʔλόΠϯσΟϯάͰͳͯ͘ํ޲ͷϦΞΫςΟϒͳσʔλϑϩʔ w +49 w +BWB4DSJQU9.-MJLFͳهड़ PQUJPOBM

Slide 4

Slide 4 text

http://blog.atom.io/2014/07/02/moving-atom-to-react.html

Slide 5

Slide 5 text

)FMMP3FBDUKT

Slide 6

Slide 6 text

)FMMP3FBDU /** @jsx React.DOM */ // ComponentΛ࡞੒ var App = React.createClass({ render: function() { return (

Hello React

); } }); // DOMͱ

ͱ͍͏componentΛඥ෇͚Δ React.render(

, document.getElementById('app') );

Slide 7

Slide 7 text

)FMMP+49 w )5.-ͷEJWཁૉʹݟ͑Δ͚ͲɺEJW΋3FBDUͰఆٛ͞Εͨ $PNQPOFOU w ʮDMBTTlIPHFzʯͰ͸ͳͯ͘ʮDMBTT/BNFlIPHFzʯ render() { var style = { backgroundColor: ‘white’, }; return (
xxx
); renderͰฦ͢component͸1ͭ

Slide 8

Slide 8 text

4UBSUXJUI+49 w +495SBOTGPSNFSΛ࢖ͬͯΦϯϥΠϯͰม׵ w SFBDUUPPMTΛ࢖ͬͯDPNNBOEMJOFͰม׵ % npm install -g react-tools % jsx --watch src/ build/ # require͢ΔͳͲͯ͠React͕scopeͷதͰݟ͑Δඞཁ͕͋Δ var React = require(‘react’);

Slide 9

Slide 9 text

4UBSUXJUI+49 w HSVOUɺHVMQɺCSPXTFSJGZUSBOTGPSNͳͲେମ͋ΔͷͰ͓޷ΈͰ w HSVOUSFBDU w HVMQSFBDU w SFBDUJGZ w IUUQTHJUIVCDPNGBDFCPPLSFBDUXJLJ$PNQMFNFOUBSZ5PPMT

Slide 10

Slide 10 text

4UBSUXJUIPVU+49 w +BWB4DSJQUͰॻ͘͜ͱ͸ग़དྷΔ͚Ͳɺ+49Ͱॻ͍ͨ΄͏͕Θ͔Γ΍ ͍͢ͷͰΦεεϝ͸͠ͳ͍ // JavaScript React.render( React.DOM.h1(null, 'Hello, world!'), document.getElementById('example') ); // JSX React.render(

Hello, world!

, document.getElementById('example') );

Slide 11

Slide 11 text

&4 4VQQPSU

Slide 12

Slide 12 text

&4 4VQQPSU w IBSNPOZPQUJPO͕͋ΔͷͰ༗ޮʹͯ͠ม׵͢Δ͜ͱͰҰ෦ͷ&4 ͷGFBUVSFΛ࢖༻͢Δ͜ͱ͕ग़དྷΔ w ͜ͷลΓ͕IBSNPOZPQUJPOʹΑͬͯ࢖͑ΔͬΆ͍ 'harmony': [ 'es6-arrow-functions', 'es6-object-concise-method', 'es6-object-short-notation', 'es6-classes', 'es6-rest-params', 'es6-templates', 'es6-destructuring', 'es7-spread-property' ], https://github.com/facebook/react/blob/master/vendor/fbtransform/visitors.js#L31-L40 % jsx —harmony src/ build/

Slide 13

Slide 13 text

&44VQQPSU w SFBDUJGZͰ΋PQUJPOΛࢦఆ͢Δ͚ͩͰ࢖͑Δ w ͦͷ݁Ռɺ͜Μͳײ͡Ͱॻ͚Δ "browserify": { "transform": [ [ "reactify", { "harmony": true } ], ] } module.exports = React.createClass({ render() { var tracks = this.props.tracks.map( (track, index) => { return (
  • {track.name} {track.artist.name}
  • ); }); return (
      {tracks}
    ); } });

    Slide 14

    Slide 14 text

    SFBDUCPJMFSQMBUF w ͔͜͜Β঺հ͢Δίʔυ͸Լهͷߏ੒ w 5SBOTGPSN͸CSPXTFSJGZSFBDUJGZ w IBSNPOZPQUJPOΛ࢖༻ w HJUIVCDPNLPCBSFBDUCPJMFSQMBUF http://koba04.github.io/react-boilerplate/

    Slide 15

    Slide 15 text

    $PNQPOFOU

    Slide 16

    Slide 16 text

    $PNQPOFOU w 7JFXΛߏ੒͢ΔύʔπͰɺ$PNQPOFOUΛ૊Έ߹ΘͤΔ͜ͱͰ7JFX Λ࡞͍ͬͯ͘ w ޙड़ͷ1SPQ΍4UBUFͰ΍ΓͱΓͯ͠$PNQPOFOUΛ࡞͍ͬͯ͘ var React = require(‘React’); var App = React.createClass({ render: function() { return (

    Hello {this.props.name}

    ); } }); React.render(

    , document.getElementById('app') );

    Slide 17

    Slide 17 text

    1SPQ

    Slide 18

    Slide 18 text

    1SPQ w $PNQPOFOU͕΋ͭ*NNVUBCMFͳ1SPQFSUZ w $PNQPOFOUͷ࡞੒࣌ʹࢦఆ͢Δ͜ͱ͕ग़དྷͯɺUIJTQSPQTYYYͰ ࢀর͢Δ w QSPQTDIJMESFOͰ$PNQPOFOU಺ͷཁૉΛऔಘ͢Δ͜ͱ͕ग़དྷΔ var Sample = React.createClass({ render() { return (
    {this.props.header}
    {this.props.children}
    ); } }); React.render(content, el);

    Slide 19

    Slide 19 text

    1SPQ5ZQFT

    Slide 20

    Slide 20 text

    1SPQ5ZQFT w 1SPQͷ஋ʹରͯ͠ܕ΍ඞਢͳͲͷࢦఆΛ͢Δ͜ͱ͕ग़དྷΔ w ഑ྻɺจࣈྻɺ਺஋ɺΦϒδΣΫτҎ֎ʹ΋ɺ3FBDU$PNQPOFOUɺ FOVN΍ΧελϜͷ7BMJEBUPSͳͲॊೈʹࢦఆग़དྷΔ w IUUQGBDFCPPLHJUIVCJPSFBDUEPDTSFVTBCMFDPNQPOFOUTIUNM module.exports = React.createClass({ propTypes: { onHandleSubmit: React.PropTypes.func.isRequired, // ؔ਺Ͱඞਢ countries: React.PropTypes.array.isRequired // ഑ྻͰඞਢ },

    Slide 21

    Slide 21 text

    4UBUF

    Slide 22

    Slide 22 text

    4UBUF w ϢʔβʔʹΑΔૢ࡞΍"1*ϦΫΤετʹΑΓɺঢ়ଶ͕มԽ͢Δ஋ module.exports = React.createClass({ getInitialState() { // stateͷॳظԽΛߦ͏ return { // stateͷΦϒδΣΫτΛฦ͢ artist: 'radiohead' }; }, handleInput(e) { this.setState({artist: e.target.value}); ɹɹɹɹɹɹ// stateͷ஋Λߋ৽͢Δ }, render() { return (
    input: {this.state.artist}
    // stateͷ஋Λࢀর͢Δ
    ); } });

    Slide 23

    Slide 23 text

    4UBUF-JOLFE4UBUF.JYJO w -JOLFE4UBUF.JYJOΛ࢖͏͜ͱʹΑΓɺXBZͳσʔλόΠϯσΟϯ ά΋؆୯ʹॻ͚Δ var React = require(‘react/addons’); // addonsΛ࢖͏৔߹͸ɺreact/addonsΛ࢖͏ module.exports = React.createClass({ mixin: [React.addons.LinkedStateMixin], getInitialState() { return { artist: 'radiohead' }; }, render() { return (
    input: {this.state.artist}
    ); } });

    Slide 24

    Slide 24 text

    1SPQ4UBUF

    Slide 25

    Slide 25 text

    1SPQ4UBUF w جຊతʹ͸1SPQͰߟ͑Δ w 4UBUFʹͨ͠஋Λࢠ$PNQPOFOUʹ౉͢৔߹͸ɺ1SPQͱͯ͠౉͢ w $PNQPOFOUͷPXOFSPXOFFͷؔ܎Λҙࣝ͢Δ w ͳΔ΂͘*NNVUBCMFͳ$PNQPOFOUΛ࡞Δ͜ͱΛҙࣝ͢Δ

    Slide 26

    Slide 26 text

    w 1BSFOU͕ߋ৽͞ΕΔͱ$IJME΋SFSFOEFS͞ΕΔ 1SPQ4UBUF Parent state = { current: “artist”, count: 10 } ChildB ChildA Prop = { current: “artist” } Prop = { count: 10 } pass as prop

    Slide 27

    Slide 27 text

    $PNQPOFOU-JGFDZDMF

    Slide 28

    Slide 28 text

    $PNQPOFOU-JGFDZDMF w $PNQPOFOUͷ-JGFDZDMFʹԠͯ͡ϝιου͕ݺ͹ΕΔ componentWillMount() DOMπϦʔʹ௥Ճ͞ΕΔલʹҰ౓͚ͩݺ͹ΕΔͷͰॳظԽॲཧΛߦ͏ͷʹద͍ͯ͠Δ ͜ͷதͰsetStateݺΜͰ΋render࣌ʹ·ͱΊͯߦΘΕΔ ServerSide Rendering࣌ʹ΋ݺ͹ΕΔ componentDidMount() DOMπϦʔʹ௥Ճ͞Εͨঢ়ଶͰݺ͹ΕΔͷͰDOMʹؔΘΔॳظԽॲཧΛ͍ͨ͠ͱ͖ʹద͍ͯ͠Δ ·ͨ͸ServerSide Rendering࣌ʹݺΜͰ΄͘͠ͳ͍ॳظॲཧʹ΋ద͍ͯ͠Δ componentWillReceiveProps (nextProps) Prop͕ߋ৽͞ΕΔ࣌ʹݺ͹ΕΔ this.props͸ݹ͍஋Ͱ৽͍͠Prop͸Ҿ਺Ͱ౉ͬͯ͘Δ shouldComponentUpdate (nextProps, nextState) ৽͍͠State͔PropΛड͚औͬͨࡍʹrerender͢Δ͔Ͳ͏͔ΛbooleanͰฦ͢ɻfalseʹ͢ Δͱߋ৽͠ͳ͍ɻperformaceͷվળ͍ͨ͠ͱ͖ʹ͜͜Ͱௐ੔͢Δ͜ͱ͕ग़དྷΔ componentWillUpdate (nextProps, nextState) component͕ߋ৽͞ΕΔ࣌ʹݺ͹ΕΔɻߋ৽લͷPropͱState͸Ҿ਺ͰऔಘͰ͖Δ ͜ͷதͰsetStateΛݺͿ͜ͱ͸ग़དྷͳ͍ componentDidUpdate (prevProps, prevState) component͕ߋ৽͞Εͨޙʹݺ͹ΕΔ ߋ৽લͷPropͱState͸Ҿ਺ͰऔಘͰ͖Δ componentWillUnmount() Component͕DOM͔Β࡟আ͞ΕΔͱ͖ʹݺ͹ΕΔ ΫϦʔϯΞοϓॲཧʹద͍ͯ͠Δ

    Slide 29

    Slide 29 text

    $PNQPOFOU-JGFDZDMF // tracks͸Backbone.Collection // tracks༻ͷmixin(ޙड़) module.exports = { componentWillMount() { this.tracks = tracks; tracks.on("all", this.setTracks); // ΠϕϯτΛߪಡ }, componentWillUnmount() { tracks.off("all", this.setTracks); // ΠϕϯτΛղআ }, setTracks() { this.setState({ tracks: tracks.map( (track) => { return track.attributes } ) }); }, };

    Slide 30

    Slide 30 text

    'FUDIJOJUJBMEBUB

    Slide 31

    Slide 31 text

    'FUDIJOJUJBMEBUB w $PNQPOFOUʹඞཁͳσʔλ͕͋Δ৔߹͸DPNQPOFOU%JE.PVOUͰ "KBY3FRVFTUΛߦ͏ͱΑ͍ w 4FSWFS4JEF3FOEFSJOH࣌ʹ΋ݺͼ͍ͨ৔߹͸8JMM.PVOUͰ w 3FTQPOTFΛTFU4UBUF͢Δͱ͖͸ɺ$PNQPOFOU͕·ͩNPVOU͞Ε ͍ͯΔ͔ΛJT.PVOUFE ͰνΣοΫͨ͠ํ͕͍͍ componentDidMount() { this.tracks = tracks; tracks.on("all", this.setTracks); }, setTracks() { if (this.isMounted()) { this.setState({ tracks: tracks.map( (track) => { return track.attributes } ) }); } },

    Slide 32

    Slide 32 text

    1BSFOUDIJMEDPNNVOJDBUJPO

    Slide 33

    Slide 33 text

    1BSFOUDIJMEDPNNVOJDBUJPO w جຊతʹ͸ࢠ͕*'Λ1SPQͰެ։ͯ͠਌͕࢖͏ܗʹ͢Δ w QSPQ5ZQFTͰ੍໿Λࢦఆ͓ͯ͘͠ͱΘ͔Γ΍͍͢ var Parent = React.createClass({ search() { console.log(“search”); }, render() { return
    } }); var Child = React.createClass({ propTypes: { onHandleClick: React.PropTypes.func.isRequired, ɹ}, handleClick() { this.props.onHandleClick() }, render() { return
    click
    } });

    Slide 34

    Slide 34 text

    1BSFOUDIJMEDPNNVOJDBUJPO w UIJTIBOEMF$MJDLCJOE UIJT J ͷΑ͏ʹҾ਺Λ౉ͯ͠਌$PNQPOFOU ಺Ͱॲཧ͢Δํ๏΋͋Δ var Sample = React.createClass({ handleClick(i) { console.log('click' + this.props.items[i]); }, render() { var items = this.props.items.map( (item, i) => { return
    {item}
    }); return
    {items}
    ); } });

    Slide 35

    Slide 35 text

    1BSFOUDIJMEDPNNVOJDBUJPO w SFGΛ࢖ͬͯࢠ$PNQPOFOUͷࢀরΛऔಘग़དྷΔ w ޙड़ͷHFU%0./PEFͱ૊Έ߹Θͤͯɺ3FBDU͕ఏڙ͍ͯ͠ΔJOQVU ͳͲͷ$PNQPOFOUʹର͢ΔࢀরΛऔಘ͢Δ͜ͱʹ࢖͏͜ͱ͸͋Δ ͚Ͳɺجຊతʹ͸ආ͚ͨํ͕͍͍ w 1SPQΛ*'ͱͨ͠ํ͕ݟ௨͕͍͍͠ w %0.΁ͷࢀরΛऔಘͰ͖Δ componentDidMount() { this.refs.input.getDOMNode().focus(); } render() { return ( ) }

    Slide 36

    Slide 36 text

    DIJMESFO

    Slide 37

    Slide 37 text

    DIJMESFO w QSPQTDIJMESFO͸഑ྻͩͬͨΓจࣈྻͩͬͨΓ͢ΔͷͰɺૢ࡞ͨ͠ Γ਺Λऔಘ͢Δͱ͖͸3FBDU$IJMESFOͷ6UJMΛ࢖͏ͱ͍͍ ͦΜͳ ʹͳ͍ͱࢥ͏͚Ͳ w 3FBDU$IJMESFO NBQcGPS&BDIcDPVOUcPOMZ ͕͋Δ w \GBMTF^౉͢͜ͱͰۭͷࢠཁૉΛදݱͰ͖Δ // span componentͷ഑ྻ
    xxxxxx
    // “xxx”ͱ͍͏จࣈྻ
    xxx
    React.Children.map(this.props.children, (child) => { … });

    Slide 38

    Slide 38 text

    5SBOTGFSJOH1SPQT

    Slide 39

    Slide 39 text

    5SBOTGFSJOH1SPQT w +49TQSFBEBUUSJCVUFTΛ࢖͏͔ɺ0CKFDUBTTJHOͳͲΛ࢖͏ w طଘͷ$PNQPOFOUΛ֦ு͍ͨ͠Α͏ͳ৔߹ʹ࢖͏ͱศར w ͨͩɺґଘ͍ͯ͠Δ1SPQ͕Θ͔Γʹ͘͘ͳΔͷͰ஫ҙ͕ඞཁ var Avatar = React.createClass({ render: function() { return ( var {userId, ...other} = this.props; ); } }); //

    Slide 40

    Slide 40 text

    3FBDU$PNQPOFOUT http://react-components.com/

    Slide 41

    Slide 41 text

    %0.&WFOU

    Slide 42

    Slide 42 text

    &WFOU

    Slide 43

    Slide 43 text

    &WFOU w Ϋϩεϒϥ΢βରԠͨ͠ωΠςΟϒ"1*ͱಉ͡*'Λ΋ͭಠࣗΠϕϯ τΛ͍࣋ͬͯΔ 4ZOUIFUJD&WFOU w ಺෦Ͱ͸SPPUͷཁૉʹ͚ͩ&WFOU-JTUFOFSΛొ࿥ͯ͠ɺ$PNQPOFOU ͱΠϕϯτʹର͢ΔϚοϐϯάΛ࣋ͬͯॲཧ͍ͯ͠Δ w ΠϕϯτϋϯυϥʔͷDPOUFYU͸DPNQPOFOUͷΠϯελϯεʹͳΔ w UPVDIΠϕϯτΛ༗ޮʹ͍ͨ͠৔߹͸ɺˣͷΑ͏ʹ༗ޮʹ͢Δඞཁ ͕͋Δ // handleSubmit(e) { // e͸SyntheticEvent e.preventDefault(); var artist = this.state.inputArtist; if (artist) { this.props.onHandleSubmit(artist); } },

    Slide 44

    Slide 44 text

    &WFOU w UPVDIΠϕϯτΛ༗ޮʹ͍ͨ͠৔߹͸ɺˣͷΑ͏ʹ༗ޮʹ͢Δඞཁ ͕͋Δ w 3FBDU͕ఏڙͯ͠ͳ͍%0.ͷΠϕϯτΛߪಡ͍ͨ͠৔߹͸ DPNQPOFOU%JE.PVOUͰBEE&WFOU-JTUFOFSͯ͠ɺ DPNQPOFOU8JMM6ONPVOUͰSFNPWF&WFOU-JTUFOFS͢Δ React.initializeTouchEvents(true); componentDidMount() { window.addEventListener('resize', this.handleResize); }, componentWillUnmount() { window.removeEventListener('resize', this.handleResize); },

    Slide 45

    Slide 45 text

    HFU%0./PEF

    Slide 46

    Slide 46 text

    HFU%0./PEF w $PNQPOFOU͕؅ཧ͍ͯ͠Δ%0.΁ͷࢀরΛऔಘ͢Δ͜ͱ͕ग़དྷΔ w SFGͱ૊Έ߹Θͤͯ࢖͏͜ͱ͕ଟ͍ componentDidMount() { this.refs.input.getDOMNode().focus(); } render() { return ( ) }

    Slide 47

    Slide 47 text

    'PSN

    Slide 48

    Slide 48 text

    'PSN$POUSPMMFE$PNQPOFOUT w WBMVFଐੑΛࢦఆ͢ΔͱɺWBMVFͷ஋ͱද্ࣔͷ஋͕ಉظ͞ΕΔͷ Ͱɺݻఆ஋Λࢦఆͨ͠৔߹͸஋͕มߋͰ͖ͳ͍ w TUBUFʹͯ͠TFU4UBUF͢Δ͜ͱͰ஋ͱද্ࣔͷ஋͕ߋ৽͞ΕΔ w IUUQKTpEEMFOFULPCBYIGQH : onHandleChange(e) { this.setState({value: e.target.value}); }

    Slide 49

    Slide 49 text

    'PSN6O$POUSPMMFE$PNQPOFOUT w WBMVFଐੑΛࢦఆ͠ͳ͍৔߹͸ɺೖྗͨ͠஋͕ͦͷ··൓ө͞ΕΔɻ EFGBVMU7BMVFΛࢦఆ͢Δ͜ͱͰॳظ஋ͷઃఆ͕Մೳ w IUUQKTpEEMFOFULPCBSYK[RSW w ࢀߟ%0.ͷWBMVFͱHFU"UUSJCVUF lWBMVFz ͰऔಘͰ͖Δ஋ͷҧ͍ w IUUQKTpEEMFOFULPCBLRVHE : onHandleChange: function(e) { this.setState({value: e.target.value}); }

    Slide 50

    Slide 50 text

    'PSN5FYU"SFBBOE4FMFDU#PY w UFYUBSFB w WBMVFʹ஋Λࢦఆ͢ΔɻUFYUBSFBYYUFYUBSFBͷࢦఆΛ͢Δ ͱEFGBVMU7BMVFͱͯ͠ѻΘΕΔ w TFMFDU w WBMVFʹ஋Λࢦఆ͢ΔɻNVMUJQMFͱͯ͠഑ྻΛࢦఆग़དྷΔ A B

    Slide 51

    Slide 51 text

    .JYJOBEEPOT

    Slide 52

    Slide 52 text

    .JYJO

    Slide 53

    Slide 53 text

    .JYJO w $PNQPOFOUͷڞ௨ͷৼΔ෣͍Λ.JYJOͱͯ͠ڞ௨Խ͢Δ͜ͱ͕ग़དྷ Δ // tracks-mixin.jsx module.exports = { getInitialState() { return { tracks: [] }; }, componentWillMount() { this.tracks = tracks; tracks.on("all", this.setTracks); }, componentWillUnmount() { tracks.off("all", this.setTracks); }, setTracks() { this.setState({ tracks: tracks.map( (track) => { return track.attributes } ) }); }, };

    Slide 54

    Slide 54 text

    .JYJO w ࢖͏࣌͸NJYJOTʹࢦఆ͢Δ͚ͩ w HFU*OJUJBM4UBUFͰಉ͡LFZΛࢦఆ͢ΔͱΤϥʔʹͳΔ var TracksMixin = require(‘../tracks-mixin.jsx'); module.exports = React.createClass({ mixins: [TracksMixin], fetchArtist(artist) { this.tracks.fetchByArtist(artist); }, getInitialState() { return { foo: “bar”, // tracks: [] ࢦఆ͢ΔͱΤϥʔʹͳΔ }; } });

    Slide 55

    Slide 55 text

    BEEPOT

    Slide 56

    Slide 56 text

    $44$MBTT.BOJQVMBUJPO

    Slide 57

    Slide 57 text

    $44$MBTT.BOJQVMBUJPO w Α͋͘Δ$44ͷDMBTTΛૢ࡞͢Δ΋ͷ render() { var classes = React.addons.classSet({ ‘is-active’: this.props.item.isActive, ‘is-important’: this.props.item.isImportant }); return (
    {this.props.item.name
    ): }

    Slide 58

    Slide 58 text

    "OJNBUJPO

    Slide 59

    Slide 59 text

    "OJNBUJPO w "OHVMBSKTͷOHBOJNBUFʹΠϯεύΠΞ͞Ε͍ͯΔΒ͍͠ w Ξχϝʔγϣϯ͍ͤͨ͞ཁૉΛ$445SBOTJUJPO(SPVQͰғΜͰΞχ ϝʔγϣϯͷ$44Λॻ͘ // ϖʔδભҠ࣌ʹΞχϝʔγϣϯͤ͞Δ(with react-router) var App = React.createClass({ propTypes: { activeRouteHandler: React.PropTypes.func.isRequired }, render() { var CSSTransitionGroup = React.addons.CSSTransitionGroup; return ( // Ξχϝʔγϣϯͷ໊લ΋ࢦఆ͢Δ {this.props.activeRouteHandler()} ); } });

    Slide 60

    Slide 60 text

    "OJNBUJPO /* transitionName͕route (stylus) */ .route-enter -webkit-animation: fadein 0.5s -webkit-animation-delay: 0.2s animation: fadein 0.5s animation-delay: 0.2s opacity: 0 .route-enter-active … .route-leave -webkit-animation: fadeout 0.2s animation: fadeout 0.2s .route-leave-active … @keyframes fadein 0% transform: scale(0.5) -webkit-transform: scale(0.5) opacity: 0 …

    Slide 61

    Slide 61 text

    "OJNBUJPO w Ξχϝʔγϣϯ։࢝࣌ʹ3FBDU$445SBOTJUJPO(SPVQ͸Ϛ΢ϯτ͞ Ε͍ͯΔඞཁ͕͋Δ w Ξχϝʔγϣϯର৅ͷཁૉʹ͸LFZଐੑΛ͚ͭΔඞཁ͕͋Δ w USBOTJUJPO &OUFSc-FBWF ʹΑͬͯFOUFS MFBWFͷͲͪΒ͔ͷΈΞχ ϝʔγϣϯͤ͞Δ͜ͱ΋ग़དྷΔ w ࡉ੍͔͍ޚΛ͍ͨ͠৔߹͸ɺ3FBDU5SBOTJUJPO(SPVQΛ࢖͏
    {item}

    Slide 62

    Slide 62 text

    5FTU

    Slide 63

    Slide 63 text

    5FTU w 3FBDUBEEPOT5FTU6UJMTͱͯ͠6UJMܥ͕αϙʔτ͞Ε͍ͯΔ w 4JNVMBUPS͕ศརͦ͏ w IUUQGBDFCPPLHJUIVCJPSFBDUEPDTUFTUVUJMTIUNM w ࣮ࡍɺࢼͯ͠ͳ͍͚Ͳʜ var node = this.refs.input.getDOMNode(); React.addons.TestUtils.Simulate.click(node); React.addons.TestUtils.Simulate.change(node); React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});

    Slide 64

    Slide 64 text

    1FSGPSNBODF

    Slide 65

    Slide 65 text

    1FSGPSNBODF w 7JSUVBM%0.ͷEJ⒎Λܭࢉͯͦ͠ͷ෦෼͚ͩΛ࣮ࡍͷ%0.ʹ൓ө͠ ͯ͘ΕΔͷͰύϑΥʔϚϯεʹ༏Ε͍ͯΔ w ίʔυΛॻ͘ͱ͖ʹ%0.ؔ࿈ͷύϑΥʔϚϯεΛ͋·Γҙࣝͨ͘͠ ͳ͍ਓʹͱͬͯ΋3FBDUKTʹ೚͓ͤͯ͘͜ͱ͕ग़དྷΔͷͰΑͦ͞͏ w γϏΞʹύϑΥʔϚϯε͕ٻΊΒΕΔΑ͏ͳ৔߹͸ɺ TIPVME$PNQPOFOU6QEBUFͰSFOEFSपΓͷνϡʔχϯάΛ͢Δ͜ͱ ΋ग़དྷΔ w 1VSF3FOEFS.JYJOΛ࢖͑Δ৔߹͸࢖͏͜ͱͰύϑΥʔϚϯε͕͕͋ Δ͜ͱ΋ w 1FSGPSNBODF5PPMT΋BEEPOͰެࣜʹఏڙ͞Ε͍ͯΔ

    Slide 66

    Slide 66 text

    1FSGPSNBODF w DIJMEʹLFZΛࢦఆ͢Δ͜ͱͰ%0.Λ࠶ར༻ͯ͘͠ΕΔ͜ͱ΋͋Δ w 4UZMF͸จࣈྻͰͳͯ͘ɺΦϒδΣΫτͰࢦఆ͢Δ renderA:
    first
    renderB:
    secondfirst
    => [replaceAttribute textContent 'second'], [insertNode first] renderA:
    first
    renderB:
    secondfirst div> => [insertNode second] renderA:
    renderB:
    => [removeStyle color], [addStyle font-weight 'bold']

    Slide 67

    Slide 67 text

    "SDIJUFDUVSF

    Slide 68

    Slide 68 text

    'MVY

    Slide 69

    Slide 69 text

    'MVY w 'BDFCPPL͕ఏএ͍ͯ͠ΔΞʔΩςΫνϟ w ΞΫγϣϯͱ͍͏୯ҐͰΠϕϯτΛ %JTQBUDIFSܦ༝Ͱ΍ΓͱΓͯ͠ɺํ޲ͳॲ ཧͷྲྀΕΛ࡞Δ w 3FBDUΛ࢖ͬͯେن໛ΞϓϦΛ࡞Ζ͏ͱ͢Δ ͱ͜͏͍͏ઃܭʹͳΔͷ΋Θ͔Δؾ͕͢Δ w ৄࡉ͸ผ్Ͱʜ w IUUQGBDFCPPLHJUIVCJPqVY https://speakerdeck.com/fisherwebdev/fluxchat#11

    Slide 70

    Slide 70 text

    #BDLCPOF

    Slide 71

    Slide 71 text

    #BDLCPOF w 3FBDU͸.7$Ͱ͍͏7ͳͷͰɺ͋Δఔ౓ͷن໛ʹͳΔͱ.PEFMͱ͠ ͯ#BDLCPOFΛ࢖͏ํ๏΋ w CBDLCPOFSFBDUDPNQPOFOUͳΜ͍ͯ͏ͷ΋͋Δ w IUUQTHJUIVCDPNNBHBMIBTCBDLCPOFSFBDUDPNQPOFOU componentWillMount() { tracks.on("all", this.setTracks); }, componentWillUnmount() { tracks.off("all", this.setTracks); },

    Slide 72

    Slide 72 text

    3PVUFS

    Slide 73

    Slide 73 text

    3PVUFS w #BDLCPOF3PVUFSͰ΋EJSFDUPSͰ΋޷͖ͳ΋ͷΛ࢖͏ w SFBDUSPVUFS΍SFBDUSPVUFSDPNQPOFOUͱ͍͏$PNQPOFOUͰ ϧʔςΟϯάΛఆٛ͢ΔΑ͏ͳ΋ͷ΋͋Δ var Router = require(‘react-router-component’); var Locations = Router.Locations, Location = Router.Location ; var route = { };

    Slide 74

    Slide 74 text

    4FSWFS4JEF3FOEFSJOH

    Slide 75

    Slide 75 text

    4FSWFS4JEF3FOEFSJOH w αʔόʔଆͰ$PNQPOFOUΛ)5.-Խͯ͠ฦ͢͜ͱ͕ग़དྷΔ w 1IBOUPN+4࢖ͬͯͷྗٕͳ͜ͱ͸͠ͳ͍͍ͯ͘ w SFBDUSBJMT΍FYQSFTTSFBDUWJFXTͱ͍͏ͷ΋ެࣜͰαϙʔτͯ͠ ͍ΔͷͰಋೖͷίετ͸ߴ͘ͳ͍ w IUUQTHJUIVCDPNSFBDUKT w SFBDUSPVUFSDPNQPOFOU͸4FSWFS4JEFͰͷ3FOEFSJOH΋αϙʔτ ͍ͯ͠ΔͷͰ૊Έ߹ΘͤΔͱ͍͍ w IUUQTHJUIVCDPNBOESFZQPQQSFBDUSPVUFSDPNQPOFOU

    Slide 76

    Slide 76 text

    4FSWFS4JEF3FOEFSJOH w SFOEFS5P4USJOHͱSFOEFS5P4UBUJD.BSLVQͷͲͪΒ͔Λ࢖ͬͯ )5.-Λੜ੒͢Δ w SFOEFS5P4USJOH w ϑϩϯτଆͰ΋3FBDUKTΛ࢖ͬͯಈతʹ͍ͨ͠৔߹ʹ࢖͏ w SFOEFS5P4UBUJD.BSLVQ w ੩తͳ)5.- ϑϩϯτଆͰ3FBDUKTΛ࢖Θͳ͍ Λੜ੒͍ͨ͠ͱ ͖ʹ࢖͏

    Slide 77

    Slide 77 text

    SFOEFS5P4USJOH w αʔόʔଆͰ)5.-Λੜ੒ͯ͠ɺΫϥΠΞϯτଆͰ͸SFOEFSͰΠϕ ϯτ͕BUUBDI͞ΕΔ͚ͩ w αʔόʔଆͰੜ੒͞ΕΔ%0.ߏ଄ͱΫϥΠΞϯτଆͰੜ੒͞ΕΔ %0.ߏ଄͕ಉ͡ʹ͢Δඞཁ͕͋Δ w 1SPQͳͲ$PNQPOFOUͷੜ੒ʹඞཁͳσʔλΛαʔόʔɺΫϥ ΠΞϯτͰڞ༗͢Δඞཁ͕͋Δ w DPNQPOFOU8JMM.PVOU͸4FSWFS4JEF3FOEFSJOH࣌ʹ΋ݺ͹ΕΔͷ ͰαʔόʔͰ΋ಈ࡞͢ΔίʔυͰ͋Δඞཁ͕͋Δ

    Slide 78

    Slide 78 text

    SFOEFS$PNQPOFOU5P4USJOH w ੜ੒͞ΕΔ)5.-ʹ͸EBUBSFBDUJEͱEBUBSFBDUDIFDLTVN͕ઃ ఆ͞ΕΔ

    Slide 79

    Slide 79 text

    SFOEFS5P4UBUJD.BSLVQ w ੩తͳ)5.- EBUBSFBDUJEͳͲ͕ͳ͍ ͕ੜ੒͞ΕΔ w ϑϩϯτଆͰ3FBDUKTΛ࢖ͬͯSFOEFS$PNQPOFOU͢Δͱɺαʔόʔ ଆͰੜ੒ͨ͠)5.-Λ࢖Θͣʹ৽͘͠%0.Λ࡞ͬͯඳը͞ΕΔ w FYQSFTTSFBDUWJFXT͸͜ͷϝιουΛ࢖͍ͬͯΔ w ੜ੒͞ΕΔ)5.-

    Slide 80

    Slide 80 text

    w XJUIFYQSFTT 4BNQMF$PEF4FSWFS4JEF require('node-jsx').install({ harmony: true }); // JSXΛparseग़དྷΔΑ͏ʹ var React = require(‘react’); var App = require('./src/index.jsx'); // ComponentΛಡΈࠐΉ var handler = function(name) { return function(req, res) { // Prop౉ͯ͠ComponentΛHTMLԽ var html = React.renderToString( React.createElement(App, { path: "/" + name }) ); res.send(html); }; }; app.get('/', handler('')); app.get('/artist', handler('artist')); app.get('/country', handler('country'));

    Slide 81

    Slide 81 text

    4BNQMF$PEF$PNQPOFOU var App = React.createClass({ render() { var title = `Artist Top Tracks (${ this.props.path })`; return ( // xxx - {title}ͱ΍Δͱ{title}ʹͳΔͷͰ஫ҙ {title} :
    ); } });

    Slide 82

    Slide 82 text

    4BNQMF$PEF$PNQPOFOU w αʔόʔଆͱΫϥΠΞϯτଆͰॲཧΛ෼͚Δ w ࣮ࡍ͸+40/Λ)5.-ʹຒΊࠐΉͳͲͰ1SPQΛڞ༗͢Δ w IUUQCFOBMQFSUDPNQSFWFOUJOHYTTKTPOIUNM var App = React.createClass({ render() {…} }); if (typeof window !== "undefined") { React.render(, document); } else { module.exports = App; }

    Slide 83

    Slide 83 text

    4BNQMF$PEF w IUUQTHJUIVCDPNLPCBSFBDUCPJMFSQMBUF w IUUQSFBDUTFSWFSTJEFSFOEFSJOHIFSPLVBQQDPN %&.0

    Slide 84

    Slide 84 text

    $PODMVTJPO

    Slide 85

    Slide 85 text

    $PODMVTJPO w ͪΐͬͱͨ͠ΞϓϦॻ͘ͳΒ7VFKTͱ͔XBZσʔλόΠϯσΟϯ άͷϥΠϒϥϦ࢖ͬͯॻ͘ͷָ͕͚ͩͲɺ͕ͬͭΓ࡞Δ࣌ͷ7JFXͱ ͯ͠3FBDUKT࢖͏ͷ͸ΞϦͳؾ͕͢Δ w 4&0͕ඞཁͳ৔໘Ͱ4FSWFS4JEF3FOEFSJOH͍͔ͨ͠Β࢖͏ͱ͍͏ બ୒΋͋Γͦ͏ w +49ͱֶ͔͋ͬͯशίετߴͦ͏ͳҹ৅͚͋ͬͨͲ"1*΋γϯϓϧ ͰެࣜಡΊ͹े෼ཧղग़དྷΔ w IUUQGBDFCPPLHJUIVCJPSFBDUEPDT

    Slide 86

    Slide 86 text

    TQFBLFSEFDLDPNLPCB HJUIVCDPNLPCBSFBDUCPJMFSQMBUF