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
React.js v0.13 changes and beyond
Search
koba04
March 30, 2015
Programming
19k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React.js v0.13 changes and beyond
Gunosy React Meetup
http://gunosy-frontend.connpass.com/event/12636/
koba04
March 30, 2015
More Decks by koba04
See All by koba04
フロントエンドの現在地とこれから
koba04
10
5.4k
Standing on the shoulders of giants
koba04
0
3.2k
React/Next によるアプリケーション開発のこれから
koba04
61
19k
フロントエンド刷新をプロジェクトとして進める際に気をつけていること
koba04
3
2.1k
How useEvent would change our applications
koba04
1
3.3k
kintoneフロントエンド刷新によるモノリスからの脱却とその先に目指す未来
koba04
3
16k
Make it Declarative with React
koba04
0
2k
Ready for React in 2019
koba04
2
1.8k
Algorithms in React
koba04
14
19k
Other Decks in Programming
See All in Programming
the container ship “Apple Silicon”@WWDC26 Recap -Japan-\(region).swift
shingangan
0
130
ここ半年くらいでAIに作らせたR用ツール
eitsupi
0
380
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
300
「人を評価する AI」の設計と実装
ryoyanara
0
210
5分で問診!Composer セキュリティ健康診断
codmoninc
0
1k
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
750
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
220
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
500
バグを直したら useEffect が消えた
colorful12
2
520
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
510
AWS DevOps AgentのAzure接続機能を検証して見えた活用法/Use Cases Verified for the AWS DevOps Agent's Azure Connectivity Feature
masakiokuda
1
240
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
180
Featured
See All Featured
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Chasing Engaging Ingredients in Design
codingconduct
0
270
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
170
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
Ruling the World: When Life Gets Gamed
codingconduct
0
300
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
240
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Skip the Path - Find Your Career Trail
mkilby
1
180
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
940
Designing for humans not robots
tammielis
254
26k
How to Talk to Developers About Accessibility
jct
2
520
Transcript
3FBDUKTWDIBOHFTBOECFZPOE (VOPTZ3FBDU.FFUVQ !LPCB
!LPCB w 8FC"QQMJDBUJPO&OHJOFFS w IUUQLPCBDPN w Ұਓ3FBDUKT"EWFOU$BMFBOEBS w IUUQRJJUBDPNBEWFOUDBMFOEBSSFBDUKT
None
None
3FBDUKTW
http://facebook.github.io/react/blog/2015/03/10/react-v0.13.html
http://blog.koba04.com/post/2015/03/05/react-js-v013-changes/
&4$MBTTFT
&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 ( <div> <p>{this.props.title}</p> <button onClick={this.onClick.bind(this)}>click</button> <p>{this.state.count}</p> </div> ); } }
&4$MBTTFT w HFU*OJUJBM4UBUFͰͳ͘ɺDPOTUSVDUPSͰTUBUFͷॳظΛࢦఆ w BVUPCJOEJOH͞Εͳ͘ͳͬͨ w NJYJOݱ࣌Ͱະαϙʔτ w IUUQTNFEJVNDPN!EBO@BCSBNPWNJYJOTBSFEFBEMPOHMJWFIJHIFS PSEFSDPNQPOFOUTBEGF
w HFU%0./PEFɺJT.PVOUFEɺSFQMBDF1SPQTɺ SFQMBDF4UBUFɺTFU1SPQTEFQSFDBUFE
1SPQJTJNNVUBCMF
1SPQJTJNNVUBCMF w 1SPQͷΛมߋ͠Α͏ͱ͢ΔͱXBSOJOH͕ग़ΔΑ͏ʹͳͬͨ w WͰ1SPQ͕*NNVUBCMFͰ͋Δ͜ͱΛલఏͱͨ͠ύϑΥʔϚ ϯεɾνϡʔχϯάΛ͢Δ͜ͱ͕త render() { // Warning:
Don't set .props.level of the React component. … var title = <title level={1} />; if (this.state.isImportant) title.props.level = 2; };
1SPQTJTJNNVUBCMF w TIPVME$PNQPOFOU6QEBUFͰมߋΛݕग़ग़དྷͳ͍ w UIJTQSPQTͱҾͰ͞ΕΔOFYU1SPQT͕ಉ͡ʹͳΔ w 3FBDUDSFBUF&MFNFOUҎޙมߋ͞Εͳ͍͜ͱΛอূ͍ͨ͠ w 1SPQ5ZQFTͷνΣοΫDSFBUF&MFNFOUͷ࣌ʹߦ͑Α͘ ͳΔ
w ωετͨ͠1SPQͷʹ͍ͭͯର֎ w ݅ʹΑͬͯ1SPQ͕ม͍͑ͨ߹ɺ3FBDUDSFBUF&MFNFOU ʹ͢1SPQΛ࡞Δ·Ͱʹ͍͍ͤ
1SPQJTJNNVUBCMF if (shouldUseFoo) { return <Foo foo={10} bar={true} />; }
else { return <Foo bar={false} />; } or var props = { bar: false }; if (shouldUseFoo) { props.foo = 10; props.bar = true; } return <Foo {...props} />;
TFU4UBUF
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
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 }
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 }); // } });
3FBDUpOE%0./PEF
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( <div> <input type=“text” ref=“inputText” /> <button onClick={this.onClick.bind(this)}>click</button> </div> ); } }
0XOFSDPOUFYUUP1BSFOU$POUFYU
0XOFSBOE1BSFOU w 1BSFOUͱ0XOFS͕Ұக͠ͳ͍DPOUFYUΛ͓͏ͱ͢Δͱ XBSOJOH͕ग़ΔΑ͏ʹͳͬͨ w 1BSFOUϕʔεͷDPOUFYU·࣮ͩ͞Ε͍ͯͳ͍ w 0XOFS 1BSFOU DPOUFYU
w VOEPDVNFOUFEGFBUVSF
0XOFSBOE1BSFOU const p = <p>title</p>; class Hoge extends React.Component {
render() { return ( <div> {p} <span>hello</span> </div> ); } } span: owner is Hoge, parent is div ! Hoge p: owner is null, parent is div ! Hoge
$POUFYU const Parent React.createClass({ static get childContextTypes() { return {
name: React.PropTypes.string } } getChildContext() { return { name: ‘parent’ } } render() { return <Child /> } } // Child render <GrandChild /> class GrandChild extends React.Component { static get contextTypes() { return { name: React.PropTypes.string } } render() { <div>{this.context.name}</div> } }
$POUFYU const child = <Child />; const Parent React.createClass({ static
get childContextTypes() { return { name: React.PropTypes.string } } getChildContext() { return { name: ‘parent’ } } render() { return <div>{child}</div> } } class Child extends React.Component { static get contextTypes() { return { name: React.PropTypes.string } } render() { <div>{this.context.name}</div> } } React.render(<Parent />, document.getElementById(‘app’)); // Warning: owner-based and parent-based contexts differ
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 };
SFGDBOQBTTBDBMMCBDL class Hello extends React.Component { onClick() { this.setState({ text:
React.findDOMNode(this._inputText).value }); } render() { return ( <div> <input type=“text” ref={(c) => this._inputText = c} /> <button onClick={this.onClick.bind(this)}>click</button> </div> ); } } w طଘͷSFGlYYYzͦͷ··͑Δ 0XOFSDPOUFYU
3FBDUDMPOF&MFNFOU
3FBDUDMPOF&MFNFOU w 3FBDUBEEPOTDMPOF8JUI1SPQTʹ͍ۙ w 1SPQͱ*NNVUBCMFͱͯ͠ѻ͏͜ͱͰDMPOF͢Δ໘͕૿͑Δ ͨΊɺίΞͷ"1*ʹͳͬͨ w ҧ͍ͱͯ͠TUZMFDMBTT/BNFͷNFSHFߦΘΕͣɺSFG͕อ ࣋͞ΕΔ var
newChildren = React.Children.map( this.props.children, child => React.cloneElement(child, { foo: true }) );
DIJMESFO
4VQQPSUJUFSBUPSTBTDIJMESFO w JUFSBUPSΛͦͷ··͢͜ͱ͕ग़དྷΔ w *NNVUBCMFKTͷ-JTUΛNBQͨ͠ͷΛࠓ·ͰUP"SSBZͨ͠Γ ͢Δඞཁ͕͋ͬͨͷ͕ͦͷ··ͤΔ render() { <ul> {Immutable.List([1,2,3]).map(i
=> <li key={i}>{i}</li>)} </ul> }
,FZFE0CKFDU
,FZFE0CKFDU w \LFZFMFNFOU^ΛDIJMESFOʹ͢ͱXBSOJOH͕ग़ΔΑ͏ʹͳͬ ͨ w Ճ͞Εͨ3FBDUBEEPOTDSFBUF'SBHNFOUΛͬͨΓNBQͰ ճͨ͠Γ͢Ε͍͍ // Keyed Object
<div>{ {a: <span />, b: <span />} }</div> // === <div><span key=“a” /><span key=“b” /></div> <div>{React.addons.createFragment({a: <span />, b: <span />})</div>
+49
UBSHFUPQUJPO w EFGBVMUFTɻ͜Ε·Ͱͷڍಈʹ͢ΔͳΒFTΛࢦఆ͢Δ w FT͕EFGBVMUʹͳΓͦ͏ͳྲྀΕ͚ͩͬͨͲɺ!TFCNDL͕FT ΛEFGBVMUʹ͢ΔΑ͏ʹ͍࣋ͬͯͬͨ
UBSHFUPQUJPO w &4DMBTTFTͰॻ͍ͨ࣌ͷϝιου͕FOVNFSBCMF͔Ͳ͏͔ͷ ҧ͍͕͋Δ class Hello extends React.Component { foo()
{ console.log("foo"); } render() { return <div>hello</div>; } }
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"); }});
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"); };
w ͱ^͕Ҏલจࣈྻͱͯ͠ѻΘΕ͍͚ͯͨͲQBSTFΤϥʔʹ ͳΔΑ͏ʹͳͬͨ BOE^BSFUSFBUFEBTBQBSTFFSSPS render() { return <div>10 > 2</div>;
// parse error! }
4IBMMPXSFOEFSJOH EPDVNFOUFE
4IBMMPXSFOEFSJOH w ֊·ͰΛSFOEFSͯ݁͠ՌΛฦ͢5FTU6UJMT w OPEFڥͰಈ࡞͢Δ w SFOEFSϝιουͷ݁ՌΛ֬ೝ͍ͨ͠ͱ͖ʹศར
4IBMMPXSFOEFSJOH class Parent extends React.Component { render() { return <div><Child
name=“child” /></div>; } } class Child extends React.Component { render() { return <div>{this.props.name}</div>; } } const shallowRenderer = React.addons.TestUtils.createRenderer(); shallowRenderer.render(<Parent />); 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 ➜
3FBDUKTW 1MBO
3FVTF$POTUBOU7BMVF5ZQFT w ಉ͡3FBDU&MFNFOUΛ͍·Θ͢͜ͱͰEJ⒎ͷίετΛݮΒ͢ w SFOEFSԿݺΕͯͦͷʹ3FBDU&MFNFOU͕࡞ΒΕΔ function render() { return <div
className="foo" />; } // ͜͏ͬͯίϯύΠϧ͢Δ(Πϝʔδ) var div = React.createElement("div", {className: “foo”}); function render() { return div; }
5BHHJOH3FBDU&MFNFOUT w 3FBDU&MFNFOUʹUBH͚Λͯ͠ɺEJ⒎ΞϧΰϦζϜΛ࠷దԽ͢ Δ <div className="foo" style={{ width: w, height:
5 }}>{c}</div> // ͜͏ͬͯίϯύΠϧ͢Δ(Πϝʔδ) { __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 } }
*OMJOF3FBDU&MFNFOUT w QSPEVDUJPOϏϧυͷ͚࣌ͩɺ3FBDUDSFBUF&MFNFOUͰͳ͘ ͯJOMJOFPCKFDUʹม͢Δ͜ͱͰίετΛݮΒ͢ w DSFBUF&MFNFOU࣌ͷ1SPQ5ZQFTʹΑΔνΣοΫͰ͖ͳ͘ͳΔ ͷͰQSPEVDUJPOϏϧυͷ͚࣌ͩ <div className="foo">{bar}<Baz key="baz"
/></div> // ͜͏ͬͯίϯύΠϧ͢Δ(Πϝʔδ) { type: 'div', props: { className: 'foo', children: [ bar, { type: Baz, props: { }, key: 'baz', ref: null } ] }, key: null, ref: null }
None
3FBDUKTW
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 <Spinner />; } return <div>Hello, {this.data.user.name} [{this.props.userID}]!</div>; } }
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 <ul> {this.data.comments.map(function(c) { return <li>{c.text}</li> })} </ul>; } });
7FSTJPOJOH
7FSTJPOJOH w ݱࡏ w 9 ͰEFQSFDBUJPOXBSOJOHTɺ9 Ͱ"1*আ w Ҡߦ w
9:ͰEFQSFDBUJPOXBSOJOHTɺ9 Ͱ"1*আ w IUUQTHJTUHJUIVCDPN[QBPFFFGDFBG
3FBDUKTW
http://facebook.github.io/react/blog/2014/03/28/the-road-to-1.0.html
3FBDUKTW w ͢ͰʹQSPEVDUJPOSFBEZ w $POUFYUͲ͏͢Δ͔ w "EEPOTͷཧɾ֎෦ϥΠϒϥϦԽ w "OJNBUJPOͷվળ w
ʜ
5IBOLZPV TQFBLFSEFDLDPNLPCB