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

Progressive Hydration #react_fukuoka

Progressive Hydration #react_fukuoka

Hiroyuki ANAI

June 05, 2019
Tweet

More Decks by Hiroyuki ANAI

Other Decks in Programming

Transcript

  1. $43POMZ w ίϯϙʔωϯτͷπϦʔ͔Β%0.Λੜ੒ɺඳը w Πϕϯτϋϯυϥʔͷઃఆ // client.js import React from

    'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( <App />, document.getElementById('root') );
  2. 443 )ZESBUJPO w αʔόʔαΠυ w ίϯϙʔωϯτπϦʔΛ)5.-ͷจࣈྻʹม׵͠ɺϨεϙϯε͢Δ • ReactDOMServer.{renderToString|renderToNodeStream} // server.js

    const ReactDOMServer = require('react-dom/server'); …省略 app.get('/', (req, res) => { const html = ReactDOMServer.renderToNodeStream( <Html><App /></Html> ); html.pipe(res); });
  3. 443 )ZESBUJPO w ΫϥΠΞϯταΠυ w 443͕ฦ͢)5.-Ͱ%0.͕ߏஙɾඳըࡁΈ w ΠϕϯτϋϯυϥʔͷઃఆͷΈΛߦ͏ w 3FBDU%0.SFOEFSͰ͸ͳ͘ɺ3FBDU%0.IZESBUFΛ࢖͏

    // client.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.hydrate( <App />, document.getElementById('root') );
  4. // app.js … let load = () => import('./stream'); let

    Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return ( <div id="app"> <Header /> <Intro /> <Hydrator load={load} /> </div> ); } BQQKT ϧʔτίϯϙʔωϯτʢ"QQʣ
  5. // app.js … let load = () => import('./stream'); let

    Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return ( <div id="app"> <Header /> <Intro /> <Hydrator load={load} /> </div> ); } $43Ͱ͸%ZOBNJD*NQPSUͰ 4USFBNίϯϙʔωϯτΛಡΈࠐΉ 4USFBNίϯϙʔωϯτ͸ #VOEMF͕෼͔Εɺ ಈతʹϒϥ΢βʹϩʔυ͞ΕΔ
  6. // app.js … let load = () => import('./stream'); let

    Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return ( <div id="app"> <Header /> <Intro /> <Hydrator load={load} /> </div> ); } 443࣌͸੩తʹ 4USFBNίϯϙʔωϯτΛಡΈࠐΉ
  7. // app.js … let load = () => import('./stream'); let

    Hydrator = ClientHydrator; if (typeof window === 'undefined') { Hydrator = ServerHydrator; load = () => require('./stream'); } export default function App() { return ( <div id="app"> <Header /> <Intro /> <Hydrator load={load} /> </div> ); } )ZESBUPSίϯϙʔωϯτ͕ 1SPHSFTTJWF)ZESBUJPOΛ࣮ߦ͢Δ QSPQTMPBE͕ฦ͢ίϯϙʔωϯτ͸ ஗Ԇͯ͠)ZESBUJPO͞ΕΔ
  8. // hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate()

    { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(<Child {...props} />, this.root); }).observe(this.root); } render() { return ( <section ref={c => this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } IZESBUPSKT )ZESBUPS$MJFOU)ZESBUPS
  9. // hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate()

    { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(<Child {...props} />, this.root); }).observe(this.root); } render() { return ( <section ref={c => this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } w TIPVME$PNQPOFOU6QEBUFͰ
 ৗʹGBMTFΛฦ͍ͯ͠ΔͷͰ
 Ξοϓσʔτ͞Εͳ͍
  10. // hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate()

    { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(<Child {...props} />, this.root); }).observe(this.root); } render() { return ( <section ref={c => this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } w ۭͷཁૉΛग़ྗɺ
 ཁૉͷSFGΛऔಘ w EBOHFSPVTMZ4FU*OOFS)5.-Ͱ
 ۭจࣈΛઃఆ͢Δͱɺ
 )ZESBUJPOΛᷖճ͢Δ
  11. // hydrator.js … export class Hydrator extends React.Component { shouldComponentUpdate()

    { return false; } componentDidMount() { new IntersectionObserver(async ([entry], obs) => { if (!entry.isIntersecting) return; obs.unobserve(this.root); const { load, ...props } = this.props; const Child = interopDefault(await load()); ReactDOM.hydrate(<Child {...props} />, this.root); }).observe(this.root); } render() { return ( <section ref={c => this.root = c} dangerouslySetInnerHTML={{ __html: '' }} suppressHydrationWarning /> ); } } w *OUFSTFDUJPO0CTFSWFSͰ
 ཁૉͷεΫϩʔϧҐஔΛ؂ࢹ w ཁૉ͕ը໘಺ʹೖͬͨΒɺ
 )ZESBUJPOΛ࣮ߦ