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

The state of React.js 2016

The state of React.js 2016

A slide for html5j #65
http://eventdots.jp/event/589181

2016/07/27: Updated about React.PureComponent

koba04

May 30, 2016
Tweet

More Decks by koba04

Other Decks in Programming

Transcript

  1. 2013 2014 2015 2016 Flux v0.13 ReactNative for iOS GraphQL

    Redux Relay React Native for Android v0.14 React Native for Windows v15.0.0 …
  2. w :PVDBODSFBUFNPTUDPNQPOFOUTBT4UBUFMFTT'VODUJPO $PNQPOFOUT 4'$  w 4'$EPFTO`UIBTBCBDLJOHJOTUBODF w /PTUBUF /PMJGFDZDMFNFUIPET

    /PSFGT w 1FSGPQUJNJTBUJPOTGPS4'$XJMMCFJOUIFGVUVSF 4UBUFMFTT'VODUJPO$PNQPOFOUT const Item = ({item}) => ( <div> <div>{item.name}×{item.count}</div> </div> ); // <Item item={{name: ‘foo’, count: 1}} />
  3. &4$MBTTFT class Counter extends React.Component { constructor(…args) {
 super(…args); this.state

    = { count: 0 }; this.onClick = this.onClick.bind(this); } onClick() { this.setState({ count: this.state.count + 1 }); } render() { return ( <div> <button onClick={this.onClick}>++<button> <div>{this.state.count}</div> </div> ); }
  4. w 4VQQPSUJOHNJOJNVN"1*T w *UEPFTO`UTVQQPSUSFQMBDF4UBUF JT.PVOUFE w .JYJOTBSFEFBE -POHMJWF)JHI0SEFS$PNQPOFOUT )0$ &4$MBTTFT$PNQPOFUT

    import shallowCompare from ‘react-addons-shallow-compare’; const pure = Component => class PureComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this, nextProps, nextState); } render () { return <Component {…this.props} /> } }; const Item = ({item}) => <div>{item.name}×{item.count}</div>; const PureItem = pure(Item);
  5. w 3FBDUDSFBUF$MBTTGFFMTPVUEBUFE w *UIBTGFBUVSFTUIBUJTDPOWFOJFOUGPSEFWFMPQFST w NJYJOH‎)JHI0SEFS$PNQPOFOUT w BVUPCJOEJOH‎&4$MBTT'JFMET4UBUJD1SPQFSUJFT  w

    *UNBZCFDPNFBTFQBSBUFQBDLBHF 3FBDUDSFBUF$MBTT class Button extends React.Component { onClick = () => this.setState({count: this.state.count + 1}); } Stage1
  6. "EE3FBDU1VSF$PNQPOFOU JOIFSJUQVSJUZGPS GVODUJPOBMDPNQPOFOUT class Post extends React.PureComponent { // or

    React.Component render() { return ( <div className="post"> <PostHeader model={this.props.model} /> <PostBody model={this.props.model} /> </div> ); } } function PostHeader(props) { // ... } function PostBody(props) { // ... } Pure Pure This wasn’t merged
  7. "QJUGBMMPGTIPVME$PNQPOFOU6QEBUF import shallowCompare from ‘react-addons-shallow-compare’; class Item extends React.Component {

    shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this, nextProps, nextState); } render() { return ( <div> <p>{this.props.name}</p> <button onClick={this.props.onClick}>click</button> </div> ); } } <Item name=“foo” onClick={() => console.log(‘click’)} />
  8. SFBDUBEEPOTQFSG w 1FSGIBTSFXSJUUFOCZ%BO"CSBNPWBUW w QSJOU%0.SFOBNFEUPQSJOU0QFSBUJPOT w :PVDBO import Perf from

    ‘react-addons-perf’; Perf.start(); ReactDOM.render(<App name="React" />, el); setTimeout(() => { ReactDOM.render(<App name="React" />, el); Perf.stop(); Perf.printWasted(); }, 1000);
  9. w 1SPQTJTJNNVUBCMF Wʙ  w 0CKFDUGSFF[F!EFW Wʙ  w "EEFE3FBDUDMPOF&MFNFOU

    Wʙ  w TFU1SPQTBOESFQMBDF1SPQTIBWFHPOF W  w 1SPQ5ZQFTJTBMFHBDZGFBUVSF w :PVDBOVTF'MPXPS5ZQF4DSJQUJOTUFBE JNDPNQBUJCMF  w *UNBZCFDPNFBTFQBSBUFEQBDLBHF 1SPQT
  10. w TFU4UBUFCFIBWFTBTCBUDIFE6QEBUFTJO&WFOU-JTUFOFS BOEMJGFDZDMFNFUIPET w :PVDBOQBTTBGVODUJPOUPTFU4UBUFGPSUSBOTBDUJPOBM VQEBUFT Wʙ 4UBUF onClick() {

    this.setState((state, props) => ({count: state.count + 1})); this.setState((state, props) => ({count: state.count + 1})); }
  11. w UIFGPMMPXJOHFYBNQMF SFOEFSPDDVSTUXPUJNFT w /PCBUDIFE6QEBUFT "QJUGBMMPGCBUDIFE6QEBUFT onClick() { fetch(API_URL) .then(res

    => res.json()) .then(json => { this.setState({user: json.user}); // … this.setState({completed: true}); }); }
  12. w 3FBDU%0.VOTUBCMF@CBUDIFE6QEBUFTQSPWJEFT CBUDIFE6QEBUFT:PVDBOBWPJEVOOFDFTTBSZSFOEFST w *U`TVOTUBCMF#VUUIF"1*JTVTFECZ3FMBZFUD VOTUBCMF@CBUDIFE6QEBUFT onClick() { fetch(API_URL) .then(res

    => res.json()) .then(json => { ReactDOM.unstable_batchedUpdates(() => { this.setState({user: json.user}); // … this.setState({completed: true}); }); }); }
  13. w 3FBDUDSFBUF&MFNFOUSFUVSOTQMBJOPCKFDU Wʙ  w /PNPSFTQBOBOEEBUBSFBDUJE FYDFQU443  Wʙ 3FBDU&MFNFOU

    // <div>Hello {name}</div> <div data-reactid=".0"> <span data-reactid=".0.0">Hello </span> <span data-reactid=".0.1">React</span> </div> <div data-reactroot> <!-- react-text: 2 -->Hello <!-- /react-text --> <!-- react-text: 3 -->React<!-- /react-text --> </div>
  14. w 4USJOH3FGJTMFHBDZ:PVTIPVMEVTFDBMMCBDL3FG w %0.$PNQPOFOUTSFUVSOJUT%0./PEFBT3FG w HFU%0./PEFTIBTHPOF W  w 3FBDU%0.pOE%0./PEFTSFUVSOTB%0./PEFGSPN

    $PNQPTJUF$PNQPOFOUT 3FG%0. render() { let text; return ( <div> <input type=“text” ref={c => c && c.focus()} /> <input type=“text” ref={c => text = c} /> </div> ); }
  15. w $POUFYUCFDPNFTBEPDVNFOUFEGFBUVSF w IUUQGBDFCPPLHJUIVCJPSFBDUEPDTDPOUFYUIUNM w *U`TBGFBUVSFGPS3FBDUMJCSBSJFT $POUFYU const Item =

    ({item}, {settings}) => ( <div className={settings.theme}>{item.name}</div> ); Item.contextTypes = { settings: React.PropTypes.object };
  16. w 8FDBOHFU4IBMMPX3FOEFSFS W  w :PVDBOUFTUGPS3FBDU$PNQPOFOUTPO/PEF FOWJSPONFOU w *UEPFTO`UTVQQPSU3FGBOEMJGFDZDMFNFUIPETDPNQMFUFMZ w

    *U`TBl4IBMMPXzSFOEFSJOH 5FTU const shallowRenderer = TestUtils.createRenderer(); const elementTree = shallowRenderer.render(<YourComponent />); assert(elementTree.props.children[0].type === ‘div’);
  17. w 5FTUJOHVUJMJUJFTGPS3FBDU$PNQPOFOUT w TIBMMPX NPVOU SFOEFS w :PVDBOUFTUGPS3FBDU$PNQPOFOUFBTJMZBOE NBJOUBJOBCMF BJSCOCFO[ZNF

    import {shallow} from ‘enzyme’; const wrapper = shallow(<YourComponent />); assert(wrapper.find(Link).prop(‘to’) === ‘/foo’); wrapper.find(‘button’).simulate(‘click’);
  18. w &4-JOUIFMQTZPVUPDSFBUF3FBDU$PNQPOFOUT w FTMJOUQMVHJOSFBDU w 3FBDUTQFDJpDMJOUJOHSVMFTGPS&4-JOU w IUUQTHJUIVCDPNZBOOJDLDSFTMJOUQMVHJOSFBDU w FTMJOUQMVHJOKTYBZ

    w 4UBUJD"45DIFDLFSGPSBDDFTTJCJMJUZSVMFTPO+49FMFNFOUT w IUUQTHJUIVCDPNFWDPIFOFTMJOUQMVHJOKTYBZ &4-JOU3FBDU
  19. w 3FBDU/BUJWFJTKVTUBSFOEFSFS 3FBDU/BUJWF import React, {Component} from 'react'; import {TabBarIOS,

    NavigatorIOS} from ‘react-native’; class App extends Component { render() { return ( <TabBarIOS> <TabBarIOS.Item title="React Native" selected={true}> <NavigatorIOS initialRoute={{ title: 'React Native' }} /> </TabBarIOS.Item> </TabBarIOS> ); } }
  20. w 3FBDU/BUJWFJTKVTUBSFOEFSFS 3FBDU/BUJWF (facebook/react) src !"" isomorphic # !"" children

    # !"" classic # $"" modern !"" renderers # !"" art # !"" dom # # !"" client # # !"" server # # $"" shared # !"" native # !"" noop # $"" shared !"" shared
  21. w 4DIFEVMJOH3FBDUSFDVSTJWFSFOEFSJOH  w $VSSFOUMZ SFDVSTJWFSFOEFSJOHJTTZODISPOPVT XIJDIJTB SFBTPO3FBDUJTTMPX <8*1>/FX3FDPODJMFS //

    src/renderers/noop/ReactNoop.js var NoopRenderer = ReactFiberReconciler({ createHostInstance() { }, scheduleHighPriCallback(callback) { scheduledHighPriCallback = callback; }, scheduleLowPriCallback(callback) { scheduledLowPriCallback = callback; },
  22. <8*1>/FX3FDPODJMFS function Continuation({ isSame }) { return <span>{isSame ? 'foo==bar'

    : 'foo!=bar'}</span>; } function Child({ bar }) { return ReactCoroutine.createYield({ bar: bar, }, Continuation, null); } function Indirection() { return [<Child bar={true} />, <Child bar={false} />]; } function HandleYields(props, yields) { return yields.map(y => <y.continuation isSame={props.foo === y.props.bar} /> ); } function Parent(props) { return ReactCoroutine.createCoroutine( props.children, HandleYields, props ); } function App() { return <div><Parent foo={true}><Indirection /></Parent></div>; } ReactNoop.render(<App />); ReactNoop.flush();