Slide 1

Slide 1 text

3FBDUKTWDIBOHFTBOECFZPOE (VOPTZ3FBDU.FFUVQ !LPCB

Slide 2

Slide 2 text

!LPCB w 8FC"QQMJDBUJPO&OHJOFFS w IUUQLPCBDPN w Ұਓ3FBDUKT"EWFOU$BMFBOEBS w IUUQRJJUBDPNBEWFOUDBMFOEBSSFBDUKT

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

3FBDUKTW

Slide 6

Slide 6 text

http://facebook.github.io/react/blog/2015/03/10/react-v0.13.html

Slide 7

Slide 7 text

http://blog.koba04.com/post/2015/03/05/react-js-v013-changes/

Slide 8

Slide 8 text

&4$MBTTFT

Slide 9

Slide 9 text

&4$MBTTFT class Hello extends React.Component { constructor(props) { super(props); this.state = { count: 0 };
 } static get propTypes() { title: React.PropTypes.string.isRequired } onClick() { this.setState({ count: this.state.count + 1 }) } render() { return (

{this.props.title}

click

{this.state.count}

); } }

Slide 10

Slide 10 text

&4$MBTTFT w HFU*OJUJBM4UBUFͰ͸ͳ͘ɺDPOTUSVDUPSͰTUBUFͷॳظ஋Λࢦఆ w BVUPCJOEJOH͞Εͳ͘ͳͬͨ w NJYJO͸ݱ࣌఺Ͱະαϙʔτ w IUUQTNFEJVNDPN!EBO@BCSBNPWNJYJOTBSFEFBEMPOHMJWFIJHIFS PSEFSDPNQPOFOUTBEGF w HFU%0./PEFɺJT.PVOUFEɺSFQMBDF1SPQTɺ SFQMBDF4UBUFɺTFU1SPQT͸EFQSFDBUFE

Slide 11

Slide 11 text

1SPQJTJNNVUBCMF

Slide 12

Slide 12 text

1SPQJTJNNVUBCMF w 1SPQͷ஋Λมߋ͠Α͏ͱ͢ΔͱXBSOJOH͕ग़ΔΑ͏ʹͳͬͨ w WͰ1SPQ͕*NNVUBCMFͰ͋Δ͜ͱΛલఏͱͨ͠ύϑΥʔϚ ϯεɾνϡʔχϯάΛ͢Δ͜ͱ͕໨త render() { // Warning: Don't set .props.level of the React component. … var title = ; if (this.state.isImportant) title.props.level = 2; };

Slide 13

Slide 13 text

1SPQTJTJNNVUBCMF w TIPVME$PNQPOFOU6QEBUFͰมߋΛݕग़ग़དྷͳ͍ w UIJTQSPQTͱҾ਺Ͱ౉͞ΕΔOFYU1SPQT͕ಉ͡ʹͳΔ w 3FBDUDSFBUF&MFNFOUҎޙ͸มߋ͞Εͳ͍͜ͱΛอূ͍ͨ͠ w 1SPQ5ZQFTͷνΣοΫ΋DSFBUF&MFNFOUͷ࣌ʹߦ͑͹Α͘ ͳΔ w ωετͨ͠1SPQͷ஋ʹ͍ͭͯ͸ର৅֎ w ৚݅ʹΑͬͯ1SPQ͕ม͍͑ͨ৔߹͸ɺ3FBDUDSFBUF&MFNFOU ʹ౉͢1SPQΛ࡞Δ·Ͱʹ౉ͤ͹͍͍

Slide 14

Slide 14 text

1SPQJTJNNVUBCMF if (shouldUseFoo) { return ; } else { return ; } or var props = { bar: false }; if (shouldUseFoo) { props.foo = 10; props.bar = true; } return ;

Slide 15

Slide 15 text

TFU4UBUF

Slide 16

Slide 16 text

TFU4UBUFDBOUBLFBGVODUJPOBTTUBSHVNFOU w τϥϯβΫγϣϯ͕ඞཁͱ͞ΕΔσʔλͷߋ৽ʹ࢖͏ w ͜Ε·Ͱ͸@QFOEJOH4UBUFΛ࢖͏ඞཁ͕͋ͬͨ console.log(this.state.count) // 0 this.setState({count: this.state.count + 1}) this.setState({count: this.state.count + 1}) // state.count will render as 1 console.log(this.state.count) // 0 this.setState(function(state, props) { return {count: state.count + 1} }); this.setState(function(state, props) { return {count: state.count + 1} }); // state.count will render as 2

Slide 17

Slide 17 text

TFU4UBUFJTBMXBZTBTZODISPOPVT w ͜Ε·ͰॳճͷϚ΢ϯτ࣌ͷݺͼग़͠͸ಉظత͚ͩͬͨͲৗʹ ඇಉظͰ#BUDIVQEBUFʹͳΔ componentDidMount() { console.log(this.state.count) // 0 this.setState({ count: this.state.count + 1 }) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) ɹ// v0.12 is 2 ɹ// v0.13 is 0 }

Slide 18

Slide 18 text

TFU4UBUFPOVONPVOUFEDPNQPOFOU w ΞϯϚ΢ϯτ͞ΕͨDPNQPOFOUͰͷTFU4UBUF GPSDF6QEBUF ͷݺͼग़ͨ࣌͠ʹΤϥʔͰͳ͘XBSOJOH͕ग़ྗ͞ΕΔΑ͏ʹ w "KBYʹର͢ΔϨεϙϯεΛTFU4UBUF͢ΔΑ͏ͳͱ͖ʹ JT.PVOUFEͰϒϩοΫ͢Δඞཁ͕ͳ͘ͳͬͨ request(‘/api/users/koba04’, (res) => { // if (this.isMounted()) { this.setState({ user: res.body.user }); // } });

Slide 19

Slide 19 text

3FBDUpOE%0./PEF

Slide 20

Slide 20 text

pOE%0./PEFJOTUFBEPGHFU%0./PEF w HFU%0./PEF͸&4$MBTTFTͰ͸ఏڙ͞Εͯͳ͍͠ DSFBUF$MBTTͰ΋XBSOJOH͕ग़ΔͷͰஔ͖׵͑Δ class Sample extends React.Component { onClick() { this.setState({ // text: this.refs.inputText.getDOMNode().value text: React.findDOMNode(this.refs.inputText).value }); } render() { return(
click
); } }

Slide 21

Slide 21 text

0XOFSDPOUFYUUP1BSFOU$POUFYU

Slide 22

Slide 22 text

0XOFSBOE1BSFOU w 1BSFOUͱ0XOFS͕Ұக͠ͳ͍DPOUFYUΛ࢖͓͏ͱ͢Δͱ XBSOJOH͕ग़ΔΑ͏ʹͳͬͨ w 1BSFOUϕʔεͷDPOUFYU͸·࣮ͩ૷͞Ε͍ͯͳ͍ w 0XOFS 1BSFOU DPOUFYU w VOEPDVNFOUFEGFBUVSF

Slide 23

Slide 23 text

0XOFSBOE1BSFOU const p =

title

; class Hoge extends React.Component { render() { return (
{p} hello
); } } span: owner is Hoge, parent is div ! Hoge p: owner is null, parent is div ! Hoge

Slide 24

Slide 24 text

$POUFYU const Parent React.createClass({ static get childContextTypes() { return { name: React.PropTypes.string } } getChildContext() { return { name: ‘parent’ } } render() { return } } // Child render class GrandChild extends React.Component { static get contextTypes() { return { name: React.PropTypes.string } } render() {
{this.context.name}
} }

Slide 25

Slide 25 text

$POUFYU const child = ; const Parent React.createClass({ static get childContextTypes() { return { name: React.PropTypes.string } } getChildContext() { return { name: ‘parent’ } } render() { return
{child}
} } class Child extends React.Component { static get contextTypes() { return { name: React.PropTypes.string } } render() {
{this.context.name}
} } React.render(, document.getElementById(‘app’)); // Warning: owner-based and parent-based contexts differ

Slide 26

Slide 26 text

SFBDUSPVUFSXJUIDPOUFYU // 0.12.x var Foo = React.createClass({ mixins: [ Router.State ], render: function () { var id = this.getParams().id; // etc. ... } }); // 0.13.x w/ ES6 fanciness class Foo extends React.Component { render () { var { router } = this.context; var id = router.getCurrentParams().id; // etc. } } Foo.contextTypes = { router: React.PropTypes.func };

Slide 27

Slide 27 text

SFGDBOQBTTBDBMMCBDL class Hello extends React.Component { onClick() { this.setState({ text: React.findDOMNode(this._inputText).value }); } render() { return (
this._inputText = c} /> click
); } } w طଘͷSFGlYYYz΋ͦͷ··࢖͑Δ 0XOFSDPOUFYU

Slide 28

Slide 28 text

3FBDUDMPOF&MFNFOU

Slide 29

Slide 29 text

3FBDUDMPOF&MFNFOU w 3FBDUBEEPOTDMPOF8JUI1SPQTʹ͍ۙ w 1SPQͱ*NNVUBCMFͱͯ͠ѻ͏͜ͱͰDMPOF͢Δ৔໘͕૿͑Δ ͨΊɺίΞͷ"1*ʹͳͬͨ w ҧ͍ͱͯ͠͸TUZMF΍DMBTT/BNFͷNFSHF͸ߦΘΕͣɺSFG͕อ ࣋͞ΕΔ var newChildren = React.Children.map( this.props.children, child => React.cloneElement(child, { foo: true }) );

Slide 30

Slide 30 text

DIJMESFO

Slide 31

Slide 31 text

4VQQPSUJUFSBUPSTBTDIJMESFO w JUFSBUPSΛͦͷ··౉͢͜ͱ͕ग़དྷΔ w *NNVUBCMFKTͷ-JTUΛNBQͨ͠΋ͷΛࠓ·Ͱ͸UP"SSBZͨ͠Γ ͢Δඞཁ͕͋ͬͨͷ͕ͦͷ··౉ͤΔ render() {
    {Immutable.List([1,2,3]).map(i =>
  • {i}
  • )}
}

Slide 32

Slide 32 text

,FZFE0CKFDU

Slide 33

Slide 33 text

,FZFE0CKFDU w \LFZFMFNFOU^ΛDIJMESFOʹ౉͢ͱXBSOJOH͕ग़ΔΑ͏ʹͳͬ ͨ w ௥Ճ͞Εͨ3FBDUBEEPOTDSFBUF'SBHNFOUΛ࢖ͬͨΓNBQͰ ճͨ͠Γ͢Ε͹͍͍ // Keyed Object
{ {a: , b: } }
// ===
{React.addons.createFragment({a: , b: })

Slide 34

Slide 34 text

+49

Slide 35

Slide 35 text

UBSHFUPQUJPO w EFGBVMU͸FTɻ͜Ε·Ͱͷڍಈʹ͢ΔͳΒFTΛࢦఆ͢Δ w FT͕EFGBVMUʹͳΓͦ͏ͳྲྀΕ͚ͩͬͨͲɺ!TFCNDL͕FT ΛEFGBVMUʹ͢ΔΑ͏ʹ͍࣋ͬͯͬͨ

Slide 36

Slide 36 text

UBSHFUPQUJPO w &4DMBTTFTͰॻ͍ͨ࣌ͷϝιου͕FOVNFSBCMF͔Ͳ͏͔ͷ ҧ͍͕͋Δ class Hello extends React.Component { foo() { console.log("foo"); } render() { return
hello
; } }

Slide 37

Slide 37 text

UBSHFUFT var ____Class0=React.Component;for(var ____Class0____Key in ____Class0) {if(____Class0.hasOwnProperty(____Class0____Key)) {Hello[____Class0____Key]=____Class0[____Class0____Key];}}var ____SuperProtoOf____Class0=____Class0===null? null:____Class0.prototype;Hello.prototype=Object.create(____SuperProtoOf____C lass0);Hello.prototype.constructor=Hello;Hello.__superConstructor__=____Class 0;function Hello(){"use strict”;if(____Class0!==null) {____Class0.apply(this,arguments);}} Object.defineProperty(Hello.prototype,"foo", {writable:true,configurable:true,value:function() {"use strict"; console.log("foo"); }}); Object.defineProperty(Hello.prototype,"render", {writable:true,configurable:true,value:function() {"use strict"; return React.createElement("div", null, "hello"); }});

Slide 38

Slide 38 text

UBSHFUFT var ____Class0=React.Component;for(var ____Class0____Key in ____Class0) {if(____Class0.hasOwnProperty(____Class0____Key)) {Hello[____Class0____Key]=____Class0[____Class0____Key];}}var ____SuperProtoOf____Class0=____Class0===null? null:____Class0.prototype;Hello.prototype=Object.create(____SuperProtoOf____C lass0);Hello.prototype.constructor=Hello;Hello.__superConstructor__=____Class 0;function Hello(){"use strict”;if(____Class0!==null) {____Class0.apply(this,arguments);}} Hello.prototype.foo=function() {"use strict"; console.log("foo"); }; Hello.prototype.render=function() {"use strict"; return React.createElement("div", null, "hello"); };

Slide 39

Slide 39 text

w ͱ^͕Ҏલ͸จࣈྻͱͯ͠ѻΘΕ͍͚ͯͨͲQBSTFΤϥʔʹ ͳΔΑ͏ʹͳͬͨ BOE^BSFUSFBUFEBTBQBSTFFSSPS render() { return
10 > 2
; // parse error! }

Slide 40

Slide 40 text

4IBMMPXSFOEFSJOH EPDVNFOUFE

Slide 41

Slide 41 text

4IBMMPXSFOEFSJOH w ֊૚·ͰΛSFOEFSͯ݁͠ՌΛฦ͢5FTU6UJMT w OPEF؀ڥͰ΋ಈ࡞͢Δ w SFOEFSϝιουͷ݁ՌΛ֬ೝ͍ͨ͠ͱ͖ʹศར

Slide 42

Slide 42 text

4IBMMPXSFOEFSJOH class Parent extends React.Component { render() { return
; } } class Child extends React.Component { render() { return
{this.props.name}
; } } const shallowRenderer = React.addons.TestUtils.createRenderer(); shallowRenderer.render(); const result = shallowRenderer.getRenderOutput(); console.assert(result.type === 'div'); console.assert(result.props.children.type === Child); console.assert(result.props.children.props.name === 'child'); console.assert(result.props.children.props.children === undefined); ➜ babel-node test.js ➜

Slide 43

Slide 43 text

3FBDUKTW 1MBO

Slide 44

Slide 44 text

3FVTF$POTUBOU7BMVF5ZQFT w ಉ͡3FBDU&MFNFOUΛ࢖͍·Θ͢͜ͱͰEJ⒎ͷίετΛݮΒ͢ w SFOEFS͸Կ౓΋ݺ͹Εͯͦͷ౓ʹ3FBDU&MFNFOU͕࡞ΒΕΔ function render() { return
; } // ͜͏΍ͬͯίϯύΠϧ͢Δ(Πϝʔδ) var div = React.createElement("div", {className: “foo”}); function render() { return div; }

Slide 45

Slide 45 text

5BHHJOH3FBDU&MFNFOUT w 3FBDU&MFNFOUʹUBH෇͚Λͯ͠ɺEJ⒎ΞϧΰϦζϜΛ࠷దԽ͢ Δ
{c}
// ͜͏΍ͬͯίϯύΠϧ͢Δ(Πϝʔδ) { __t: 7, type: 'div', props: { className: 'foo', style: { width: w, height: 5 }, children: c } } // ·ͨ͸ var t = { className: 1, style: { height: 1 } }; { __t: t, type: 'div', props: { className: 'foo', style: { width: w, height: 5 }, children: c } }

Slide 46

Slide 46 text

*OMJOF3FBDU&MFNFOUT w QSPEVDUJPOϏϧυͷ͚࣌ͩɺ3FBDUDSFBUF&MFNFOUͰ͸ͳ͘ ͯJOMJOFPCKFDUʹม׵͢Δ͜ͱͰίετΛݮΒ͢ w DSFBUF&MFNFOU࣌ͷ1SPQ5ZQFTʹΑΔνΣοΫ͸Ͱ͖ͳ͘ͳΔ ͷͰQSPEVDUJPOϏϧυͷ͚࣌ͩ
{bar}
// ͜͏΍ͬͯίϯύΠϧ͢Δ(Πϝʔδ) { type: 'div', props: { className: 'foo', children: [ bar, { type: Baz, props: { }, key: 'baz', ref: null } ] }, key: null, ref: null }

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

3FBDUKTW

Slide 49

Slide 49 text

0CTFSWBCMF"1* w IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT class Foo { observe() { return { user: loadUser(this.props.userID) }; } render() { if (this.data.user.id !== this.props.userID) { // Ensure that we never show inconsistent userID / user.name combinations. return ; } return
Hello, {this.data.user.name} [{this.props.userID}]!
; } }

Slide 50

Slide 50 text

3FBDU—1BSTF w IUUQCMPHQBSTFDPNQBSTFBOESFBDUTIBSFEDIFNJTUSZ // Render a list of comments from the Parse API var CommentBlock = React.createClass({ mixins: [ParseReact.Mixin], observe: function() { return { comments: (new Parse.Query('Comment')).descending('createdAt') }; }, render: function() { return
    {this.data.comments.map(function(c) { return
  • {c.text}
  • })}
; } });

Slide 51

Slide 51 text

7FSTJPOJOH

Slide 52

Slide 52 text

7FSTJPOJOH w ݱࡏ w 9ͰEFQSFDBUJPOXBSOJOHTɺ9Ͱ"1*࡟আ w Ҡߦ w 9:ͰEFQSFDBUJPOXBSOJOHTɺ9Ͱ"1*࡟আ w IUUQTHJTUHJUIVCDPN[QBPFFFGDFBG

Slide 53

Slide 53 text

3FBDUKTW

Slide 54

Slide 54 text

http://facebook.github.io/react/blog/2014/03/28/the-road-to-1.0.html

Slide 55

Slide 55 text

3FBDUKTW w ͢ͰʹQSPEVDUJPOSFBEZ w $POUFYUͲ͏͢Δ͔ w "EEPOTͷ੔ཧɾ֎෦ϥΠϒϥϦԽ w "OJNBUJPOͷվળ w ʜ

Slide 56

Slide 56 text

5IBOLZPV TQFBLFSEFDLDPNLPCB