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

Reactの最新動向とベストプラクティス

koba04
September 03, 2016

 Reactの最新動向とベストプラクティス

koba04

September 03, 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 … React.Component Stateless Functional Component No more span and data-reactid React. PureComponent (v15.3.0ʙ)
  2. class App extends React.Component { constructor(…args) { super(…args); this.state =

    { text: ‘’, }; } render() { return ( <TextBox text={this.state.text} onChange={text => this.setState({text})} /> ); } } const TextBox = (text, onChange) => ( <div> <input type=“text” onChange={e => onChange(e.target.value} /> <p>{text}</p> </div> ); ReactDOM.render( <App />, document.getElementById(‘app’) );
  3. w 7JFX$PNQPOFOU 4UBUF  w $PNQPOFOU͸4UBUF͔Β7JFX 3FBDU&MFNFOU Λ࡞Δ w $PNQPOFOU͸7JFXΛ࡞Δؔ਺

    w 3FBDU͕ࠩ෼Λܭࢉͯ͠%0.ʹ൓ө͢Δ w *'͸1SPQT w એݴతʹ7JFXΛߏங͢Δ w એݴతʁ 3FBDUͷಛ௃
  4. w ʮมԽʯͰ͸ͳ͘ʮঢ়ଶʯΛఆٛ͢Δ એݴతʁ // ໋ྩత // elͷมԽΛॻ͍͍ͯΔ button.on(‘click’, () =>

    el.append(child)); // એݴత // stateʹର͢Δ͋Δ΂͖දࣔΛॻ͍͍ͯΔ render = state => { el.innerHTML = state.map(child => `<div>${child}</div>`).join(‘’); }; button.on(‘click’, () => { state.push(child); render(state); }
  5. w ॳظදࣔ΋ߋ৽΋ৗʹ$PNQPOFOU 4UBUF Ͱ7JFXΛ࡞Δ એݴతʁ // ೖྗʹରͯ͠ৗʹಉ͡ग़ྗΛฦ͢ const CommentBox =

    ({comment, onChange}) => ( <div> <p>{comment}</p> <input type=“text” value={comment} onChange={e => onChange(e.target.value)} /> </div> ); const render = comment => ( ReactDOM.render( <CommentBox comment={comment} onChange={render} />, document.getElementById(‘app’) ) );
  6. w 'JSTU$IPJDF w Πϯελϯε΋࣋ͨͳ͍ͨͩͷؔ਺ w 3FBDU&MFNFOU$PNQPOFOU 1SPQT  w /PTUBUF

    /PMJGFDZDMFNFUIPET /PSFGT w কདྷతͳ࠷దԽ΋ 4UBUFMFTT'VODUJPO$PNQPOFOUT 4'$ // PropsΛड͚औΓɺReactElementΛฦؔ͢਺ const Item = ({item}) => ( <div> <div>{item.name}×{item.count}</div> </div> ); // <Item item={{name: ‘foo’, count: 1}} />
  7. w 4UBUF΍ϥΠϑαΠΫϧϝιου͕ඞཁʹͳͬͨΒ 3FBDU$PNQPOFOU class App extends React.Component { constructor(…args) {


    super(…args); this.state = { user: null, }; } componentDidMount() { fetch(‘/api/user’) .then(res => res.json()) .then(user => this.setState({user})) ; } render() { if (this.state.user == null) return <Loading />; return ( <div> <User user={this.state.user} /> </div> ); }
  8. w 4UBUFʹ͸දࣔʹඞཁͳσʔλ͚ͩ 3FBDU$PNQPOFOU class App extends React.Component { constructor(…args) {


    super(…args); // this.state = { // timerId: null, // }; } componentDidMount() { this.timerId = setInterval(() => {}, 1000); // this.setState({ // timerId: setInterval(() => {}, 1000) // }); } componentWillMount() { clearInterval(this.timerId); // clearInterval(this.state.timerId); } render() { } }
  9. w 4IPVME$PNQPOFOU6QEBUFʹ1SPQTͱ4UBUFʹର͢Δ 4IBMMPX&RVBM͕ద༻͞ΕΔ w কདྷతʹ͸$IJMESFOͷ4'$ʹରͯ͠ͷ࠷దԽ͕ೖΔ͔΋ 3FBDU1VSF$PNQPOFOU Wʙ class Counter extends

    React.PureComponent { constructor(…args) { super(…args); this.state = {count: 0}; } render() { return ( <div> <p>{this.props.label}:{this.state.count}</p> <button onClick={() => this.setState({count: this.state.count + 1}) /> </div> ); } }
  10. 1VSF$PNQPOFOUͷམͱ݀͠ class Item extends React.PureComponent { render() { return (

    <div> <p>{this.props.name}</p> <button onClick={this.props.onClick}>click</button> {this.props.children} </div> ); } } // props.onClick !== nextProps.onClick <Item name=“foo” onClick={() => console.log(‘click’)} /> // props.children !== nextProps.children <Item name=“foo” onClick={onClick}> <div>foo</div> </Item>
  11. ਪଌ͢ΔͳܭଌͤΑ w SFBDUBEEPOTQFSG 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);
  12. w ͔ͭͯͷ࡞੒ํ๏ɻ؇΍͔ʹඇਪ঑΁ w ࠷ऴతʹ͸ผύοέʔδʹʁ w 'BDFCPPL಺෦΋3FBDU$PNQPOFOU΁ͷҠߦத w 3FBDUDSFBUF$MBTTͷศརػೳͷϚΠάϨʔγϣϯύε w NJYJO⾣)JHI0SEFS$PNQPOFOUT

    w BVUPCJOEJOH⾣1VCMJD$MBTT'JFMET 3FBDUDSFBUF$MBTT class Button extends React.Component { onClick = () => this.setState({count: this.state.count + 1}); } Stage2
  13. w $PNQPTJUJPOPWFS*OIFSJUBODF w )JHIFS0SEFS'VODUJPO )JHIFS0SEFS$PNQPOFOUT // Կ͔͢Δؔ਺Λड͚औͬͯɺ݁ՌΛϩάग़ͯ͠ฦ͢ const logger =

    operation => (…args) => { const result = operation(…args); console.log(result); return result; }; const add = logger((a, b) => a + b); add(10, 20); // 30
  14. w )JHIFS0SEFS$PNQPOFOUT )JHIFS0SEFS$PNQPOFOUT // ComponentΛड͚औͬͯɺPureComponentͰϥοϓͯ͠ฦ͢ const pure = Component =>

    class Pure extends React.PureComponent {
 render() { return <Component …{this.props} />; } } const Item = ({name}) => <div>{name}</div>; const PureItem = pure(Item); // <PureItem name=“foo” />
  15. w BDEMJUFSFDPNQPTF w )JHIFS0SEFS$PNQPOFOUTͷVUJMJUZू w IUUQTHJUIVCDPNBDEMJUFSFDPNQPTF )JHIFS0SEFS$PNQPOFOUTΛ࢖͏ // isLoadedʹΑͬͯComponentΛग़͠෼͚Δ const

    enhance = branch( props => props.isLoaded, Component => Component, () => Loading ); const LoadUser = enhance(User); // <LoadUser isLoaded={isLoaded} user={user} />
  16. w SFBDUKTSFBDUSPVUFS XJUI3PVUFS  w SFBDUKTSFBDUSFEVY DPOOFDU )JHIFS0SEFS$PNQPOFOUTࣄྫ const MyPage

    = ({router}) => <div>hoge</div>; const WithRouterMyPage = withRouter(MyPage); const MyPage = ({user, updateName}) => <div>{user.name}</div>; const ConnectedMyPage = connect( mapStateToProps, mapDispatchToProps )(MyPage);
  17. w QSPQTDIJMESFOʹؔ਺Λ౉͢͜ͱͰ֦ு͢Δ w ແବͳ$PNQPOFOUʹΑΔϥοϓ͕ൃੜ͠ͳ͍ w 1SPQTͱͷিಥΛߟ͑ͳ͍͍ͯ͘ w ࠷దԽ͕೉͍͠ w SFBDUNPUJPO

    w IUUQTNFEJVNDPNNFSSJDLDISJTUFOTFOGVODUJPOBTDIJME DPNQPOFOUTGBBDF 'VODUJPOBT$IJME$PNQPOFOUT FuncAsChild = props => <div>{props.children(‘foo’)}</div>; // <FuncAsChild>{foo => <span>{foo}</span>}</FuncAsChild>
  18. w ಉ͡$PNQPOFOUͰ΋໾ׂ͸શ͘ҟͳΔ $POUBJOFS$PNQPOFOUͱ1SFTFOUBUJPOBM $PNQPOFOU Presentational Component w 7JFXͷߏஙΛ୲͏ w 4'$

    w %PNBJO-PHJDΛ஌Βͳ͍ w 4UBUF؅ཧͷ͜ͱ͸஌Βͳ͍ Container Component w ߋ৽ॲཧɺঢ়ଶ؅ཧΛ୲͏ w 3FBDU 1VSF $PNQPOFOU w %0.Λ஌Βͳ͍ w DPOOFDUͰ࡞੒ 3FEVY 
  19. 3FEVY w BDUJPO"DUJPO$SFBUPS <FWFOU>  w ΞϓϦέʔγϣϯͰൃੜ͢ΔΠϕϯτ w OFX4UBUF3FEVDFS TUBUF

    BDUJPO  w ΞϓϦέʔγϣϯͷঢ়ଶߋ৽ w QSPQT4FMFDUPS TUBUF  w 7JFXʹඞཁͳσʔλ
  20. 3FEVY w ୯Ұͷ4UBUFʹશ͕ͯ٧·͍ͬͯΔ w ⾣4UBUFΛݟΕ͹ΞϓϦέʔγϣϯͷঢ়ଶ͕Θ͔Δ w ⾣7JFX$PNQPOFOU 4UBUF  w

    σʔλͱϩδοΫͷ෼཭ w ଟ͘ͷ෦෼͕෭࡞༻ͷͳ͍ؔ਺ʹͳΔͷͰςετ͕؆୯ w ෭࡞༻͸ʁʁ
  21. w $PNQPOFOU୯ମʹର͢Δςετ͕Մೳ w ࢠ$PNQPOFOU͸SFOEFS͞Εͳ͍ w /PEF؀ڥͰςετ͕ՄೳʢKTEPNͳͲ͸ෆཁʣ w 3FGT͸ະαϙʔτɺ-JGFDZDMF.FUIPET͸Ұ෦ͷΈαϙʔτ w l4IBMMPXz3FOEFSJOH

    4IBMMPX3FOEFS const shallowRenderer = TestUtils.createRenderer(); const elementTree = shallowRenderer.render(<YourComponent />); assert(elementTree.props.children[0].type === ‘div’);
  22. w 3FBDU$PNQPOFOUTʹର͢Δςετͷ6UJMJUZ w TIBMMPX NPVOU SFOEFS w 5FTU6UJMTͷ"1*Λ࢖͏ΑΓɺ؆୯ʹɺΘ͔Γ΍͘͢ॻ͘͜ͱ͕ Մೳ BJSCOCFO[ZNF

    import {shallow} from ‘enzyme’; const wrapper = shallow(<YourComponent />); assert(wrapper.find(Link).prop(‘to’) === ‘/foo’); wrapper.find(‘button’).simulate(‘click’);
  23. w 3FBDU&MFNFOUͷπϦʔΛ+40/ʹͯ͠ฦ͢ w /PUl4IBMMPXz w -JGFDZDMF.FUIPET΋αϙʔτ͞Ε͍ͯΔ w "1*͸·ͩ·ͩ੔උத w +FTUͷTOBQTIPUUFTUJOHͰ࢖ΘΕ͍ͯΔ

    SFBDUUFTUSFOEFSFS Wʙ import renderer from ‘react-test-renderer’; const tree = renderer.create(<YourComponent />).toJSON(); assert(tree.props.children[0].type === ‘div’);
  24. &4-JOU3FBDU w OPTUSJOHSFGTʜจࣈྻʹΑΔ3FGTࢦఆͷېࢭ w QSFGFSTUBUFMFTTGVODUJPOʜ4'$ʹΑΔఆٛΛ༏ઌ͢Δ w OPEJSFDUNVUBUJPOTUBUFʜUIJTTUBUFΛ௚઀ߋ৽Λېࢭ w TPSUDPNQʜ$PNQPOFOU಺ͷϝιουఆٛॱΛνΣοΫ w

    KTYOPCJOEʜ1SPQTͰͷCJOE ΍"SSPX'VODUJPOͷېࢭ w KTYLFZʜLFZͷ1SPQT͕ඞཁͳ৔໘Ͱࢦఆ͞Ε͍ͯΔ͔ w 4FFNPSFSVMFT w IUUQTHJUIVCDPNZBOOJDLDSFTMJOUQMVHJOSFBDU
  25. 3FBM8PSMEͱ3FBDU w %FQSFDBUF1SPDFTT w ͭલͷϝδϟʔόʔδϣϯͰܯࠂ͔ͯ͠Βഇࢭ͞ΕΔ w ҠߦύεΛఏڙ w (SBEVBM"EPQUJPO w

    طଘͷΞϓϦέʔγϣϯʹ૊ΈࠐΈ΍͍͢"1*ͷఏڙ w 3FBDUXJUIK2VFSZ $BOWBTʜ w &TDBQF)BUDIFT w 3FGT EBOHFSPVTMZ4FU*OOFS)5.- $POUFYU
  26. 3FBDU$PSF w $PSF͸ͲΜͲΜখ͘͞"1*͸࠷௿ݶʹ w SFBDU w $PNQPOFOU΍3FBDU&MFNFOUΛ࡞੒͢Δ w SFOEFSFS w

    $PNQPOFOUΛϓϥοτϑΥʔϜʹԠͯ͡ॲཧ͢Δ w %0.΋ͨͩͷλʔήοτ w SFBDUEPN SFBDUOBUJWF SFBDUBSUʜ
  27. % tree src -L 3 -d . !"" addons !""

    isomorphic # !"" children # !"" classic # !"" hooks # $"" modern !"" renderers # !"" art # !"" dom # # !"" client # # !"" fiber # # !"" server # # $"" shared # !"" native # !"" noop # !"" shared # # !"" fiber # # !"" hooks # # !"" shared # # !"" stack # # $"" utils # $"" testing !"" shared !"" test $"" umd
  28. <8*1>3FBDU'JCFS w ಺෦ΞϧΰϦζϜͷશ໘ॻ͖׵͑ 3FDPODJMFS  w ༏ઌ౓ʹԠͯ͡εέδϡʔϦϯά͞Εͨඇಉظͳ7JFXͷߋ৽ w ݱࡏ͸ࠩ෼ͷݕग़ɾద༻͕ಉظతʹߦͳΘΕ͍ͯΔ w

    NTҎ಺Λ໨ࢦͦ͏ͱ͢Δͱʜ w ༏ઌ౓ͷߴ͍ॲཧ SFRVFTU"OJNBUJPO'SBNF  w ༏ઌ౓ͷ௿͍ॲཧ SFRVFTU*EMF$BMMCBDL
  29. <8*1>3FBDU'JCFS // renderers/shared/fiber/ReactPriorityLevel.js module.exports = { // No work is

    pending. NoWork: 0, // For controlled text inputs. Synchronous side-effects. SynchronousPriority: 1, // Needs to complete before the next frame. AnimationPriority: 2, // Interaction that needs to complete pretty soon to feel responsive. HighPriority: 3, // Data fetching, or result from updating stores. LowPriority: 4, // Won't be visible but do the work in case it becomes visible. OffscreenPriority: 5, };