$30 off During Our Annual Pro Sale. View Details »

Get Started React.js

koba04
September 30, 2014

Get Started React.js

React.jsについての簡単な紹介
Component化、Prop、Stateの使い分け、イベント、addon、mixin、アーキテクチャ、ServerSide Renderingなどについての説明。
一部v0.12で変わった部分の対応もしています。

koba04

September 30, 2014
Tweet

More Decks by koba04

Other Decks in Programming

Transcript

  1. (FU4UBSUFE3FBDUKT
    !LPCB
    WରԠ

    View Slide

  2. facebook.github.io/react/

    View Slide

  3. 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

    View Slide

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

    View Slide

  5. )FMMP3FBDUKT

    View Slide

  6. )FMMP3FBDU
    /** @jsx React.DOM */
    // ComponentΛ࡞੒
    var App = React.createClass({
    render: function() {
    return (
    Hello React
    );
    }
    });
    // DOMͱͱ͍͏componentΛඥ෇͚Δ
    React.render(
    ,
    document.getElementById('app')
    );

    View Slide

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


    xxx


    );
    renderͰฦ͢component͸1ͭ

    View Slide

  8. 4UBSUXJUI+49
    w +495SBOTGPSNFSΛ࢖ͬͯΦϯϥΠϯͰม׵
    w SFBDUUPPMTΛ࢖ͬͯDPNNBOEMJOFͰม׵


    % npm install -g react-tools
    % jsx --watch src/ build/
    # require͢ΔͳͲͯ͠React͕scopeͷதͰݟ͑Δඞཁ͕͋Δ
    var React = require(‘react’);

    View Slide

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

    View Slide

  10. 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')
    );

    View Slide

  11. &4 4VQQPSU

    View Slide

  12. &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/

    View Slide

  13. &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});
    }
    });

    View Slide

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

    View Slide

  15. $PNQPOFOU

    View Slide

  16. $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')
    );

    View Slide

  17. 1SPQ

    View Slide

  18. 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);

    View Slide

  19. 1SPQ5ZQFT

    View Slide

  20. 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 // ഑ྻͰඞਢ
    },

    View Slide

  21. 4UBUF

    View Slide

  22. 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ͷ஋Λࢀর͢Δ
    value={this.state.artist} />

    );
    }
    });

    View Slide

  23. 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}


    );
    }
    });

    View Slide

  24. 1SPQ4UBUF

    View Slide

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

    View Slide

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

    View Slide

  27. $PNQPOFOU-JGFDZDMF

    View Slide

  28. $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͔Β࡟আ͞ΕΔͱ͖ʹݺ͹ΕΔ
    ΫϦʔϯΞοϓॲཧʹద͍ͯ͠Δ

    View Slide

  29. $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 } )
    });
    },
    };

    View Slide

  30. 'FUDIJOJUJBMEBUB

    View Slide

  31. '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 } )
    });
    }
    },

    View Slide

  32. 1BSFOUDIJMEDPNNVOJDBUJPO

    View Slide

  33. 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
    }
    });

    View Slide

  34. 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}
    );
    }
    });

    View Slide

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

    )
    }

    View Slide

  36. DIJMESFO

    View Slide

  37. 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) => { … });

    View Slide

  38. 5SBOTGFSJOH1SPQT

    View Slide

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

    );
    }
    });
    //

    View Slide

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

    View Slide

  41. %0.&WFOU

    View Slide

  42. &WFOU

    View Slide

  43. &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);
    }
    },

    View Slide

  44. &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);
    },

    View Slide

  45. HFU%0./PEF

    View Slide

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

    )
    }

    View Slide

  47. 'PSN

    View Slide

  48. 'PSN$POUSPMMFE$PNQPOFOUT
    w WBMVFଐੑΛࢦఆ͢ΔͱɺWBMVFͷ஋ͱද্ࣔͷ஋͕ಉظ͞ΕΔͷ
    Ͱɺݻఆ஋Λࢦఆͨ͠৔߹͸஋͕มߋͰ͖ͳ͍
    w TUBUFʹͯ͠TFU4UBUF͢Δ͜ͱͰ஋ͱද্ࣔͷ஋͕ߋ৽͞ΕΔ
    w IUUQKTpEEMFOFULPCBYIGQH


    :
    onHandleChange(e) {
    this.setState({value: e.target.value});
    }

    View Slide

  49. '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});
    }

    View Slide

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


    A
    B

    View Slide

  51. .JYJOBEEPOT

    View Slide

  52. .JYJO

    View Slide

  53. .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 } )
    });
    },
    };

    View Slide

  54. .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: [] ࢦఆ͢ΔͱΤϥʔʹͳΔ
    };
    }
    });

    View Slide

  55. BEEPOT

    View Slide

  56. $44$MBTT.BOJQVMBUJPO

    View Slide

  57. $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
    ):
    }

    View Slide

  58. "OJNBUJPO

    View Slide

  59. "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()}

    );
    }
    });

    View Slide

  60. "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

    View Slide

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

    {item}


    View Slide

  62. 5FTU

    View Slide

  63. 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"});

    View Slide

  64. 1FSGPSNBODF

    View Slide

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

    View Slide

  66. 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']

    View Slide

  67. "SDIJUFDUVSF

    View Slide

  68. 'MVY

    View Slide

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

    View Slide

  70. #BDLCPOF

    View Slide

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

    View Slide

  72. 3PVUFS

    View Slide

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





    };

    View Slide

  74. 4FSWFS4JEF3FOEFSJOH

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  80. 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'));

    View Slide

  81. 4BNQMF$PEF$PNQPOFOU

    var App = React.createClass({
    render() {
    var title = `Artist Top Tracks (${ this.props.path })`;
    return (


    // xxx - {title}ͱ΍Δͱ{title}ʹͳΔͷͰ஫ҙ
    {title}
    :










    );
    }
    });

    View Slide

  82. 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;
    }

    View Slide

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

    View Slide

  84. $PODMVTJPO

    View Slide

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

    View Slide

  86. TQFBLFSEFDLDPNLPCB
    HJUIVCDPNLPCBSFBDUCPJMFSQMBUF

    View Slide