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

React Suspense on Apollo

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

React Suspense on Apollo

Avatar for Kodai Nakamura

Kodai Nakamura

August 02, 2018
Tweet

More Decks by Kodai Nakamura

Other Decks in Programming

Transcript

  1. ©2018 Wantedly, Inc. React Suspense on Apollo Meguro.es #16 @

    LIVESENSE 2nd.August.2018 - Kodai Nakamura
  2. ©2018 Wantedly, Inc. React Suspense on Apollo Meguro.es #16 @

    LIVESENSE 2nd.August.2018 - Kodai Nakamura
  3. ©2018 Wantedly, Inc. React Suspense ͳΜͰඞཁʁ ‣ 69ͷ޲্ ‣ OFUXPSL؀ڥͷҧ͍ʹରԠ͢Δ

     4QJOOFS͕Ұॠ͚ͩදࣔ͞ΕΔ  ը૾͕൒୺ͳঢ়ଶͰSFOEFS͞ΕΔ ‣ ࠓͩͱɺMPBEJOH͔Ͳ͏͔ͷνΣοΫΛ͢Δ
  4. ©2018 Wantedly, Inc. React Suspense த਎͸Ͳ͏ͳͬͯΔʁ ‣ SFOEFSϝιουͷதͰ͸DBDIF͔Β஋Λऔಘ͢Δ ‣ DBDIF͕͋Δͱ͖͸ɺී௨ʹSFOEFS

    ‣ DBDIF͕ͳ͍ͱ͖͸ɺUISPXOFX1SPNJTF͢Δ  1SPNJTF͕SFTPMWF͞Ε͍ͯͳ͍৔߹͸SFOEFS͠ͳ͍  1SPNJTF͕SFTPMWF͞ΕͨΒ࠶SFOEFS
  5. ©2018 Wantedly, Inc. React Suspense த਎͸Ͳ͏ͳͬͯΔʁ ‣ SFOEFSϝιουͷதͰ͸DBDIF͔Β஋Λऔಘ͢Δ ‣ DBDIF͕͋Δͱ͖͸ɺී௨ʹSFOEFS

    ‣ DBDIF͕ͳ͍ͱ͖͸ɺUISPXOFX1SPNJTF͢Δ  1SPNJTF͕SFTPMWF͞Ε͍ͯͳ͍৔߹͸SFOEFS͠ͳ͍  1SPNJTF͕SFTPMWF͞ΕͨΒ࠶SFOEFS 1SPNJTFΛUISPX 
  6. ©2018 Wantedly, Inc. React Suspense &SSPS#PVOEBSJFT class ErrorBoundary extends React.Component

    { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { this.setState({ hasError: true }); logErrorToMyService(error, info); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } <ErrorBoundary> <MyWidget /> </ErrorBoundary> ‣ ࢠίϯϙʔωϯτͷΤϥʔΛ਌ίϯϙʔωϯτͰ
 DBUDI͢Δ࢓૊Έ ‣ +4ͷDBUDIΈ͍ͨͳ͜ͱ͕$PNQPOFOUͰ
 Ͱ͖ΔΑ͏ʹͳΔ ‣ એݴతʹ͔͚Δ ‣ DPNQPOFOU%JE$BUDIͰัଊͰ͖Δ
  7. ©2018 Wantedly, Inc. React Suspense &SSPS#PVOEBSJFT class ErrorBoundary extends React.Component

    { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { this.setState({ hasError: true }); logErrorToMyService(error, info); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } <ErrorBoundary> <MyWidget /> </ErrorBoundary> ‣ ࢠίϯϙʔωϯτͷΤϥʔΛ਌ίϯϙʔωϯτͰ
 DBUDI͢Δ࢓૊Έ ‣ +4ͷDBUDIΈ͍ͨͳ͜ͱ͕$PNQPOFOUͰ
 Ͱ͖ΔΑ͏ʹͳΔ ‣ એݴతʹ͔͚Δ ‣ DPNQPOFOU%JE$BUDIͰัଊͰ͖Δ
  8. ©2018 Wantedly, Inc. React Suspense &SSPS#PVOEBSJFT class ErrorBoundary extends React.Component

    { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { this.setState({ hasError: true }); logErrorToMyService(error, info); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } <ErrorBoundary> <MyWidget /> </ErrorBoundary> ‣ ࢠίϯϙʔωϯτͷΤϥʔΛ਌ίϯϙʔωϯτͰ
 DBUDI͢Δ࢓૊Έ ‣ +4ͷDBUDIΈ͍ͨͳ͜ͱ͕$PNQPOFOUͰ
 Ͱ͖ΔΑ͏ʹͳΔ ‣ એݴతʹ͔͚Δ ‣ DPNQPOFOU%JE$BUDIͰัଊͰ͖Δ
  9. ©2018 Wantedly, Inc. React Suspense &SSPS#PVOEBSJFT class ErrorBoundary extends React.Component

    { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { this.setState({ hasError: true }); logErrorToMyService(error, info); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } <ErrorBoundary> <MyWidget /> </ErrorBoundary> ‣ ࢠίϯϙʔωϯτͷΤϥʔΛ਌ίϯϙʔωϯτͰ
 DBUDI͢Δ࢓૊Έ ‣ +4ͷDBUDIΈ͍ͨͳ͜ͱ͕$PNQPOFOUͰ
 Ͱ͖ΔΑ͏ʹͳΔ ‣ એݴతʹ͔͚Δ ‣ DPNQPOFOU%JE$BUDIͰัଊͰ͖Δ
  10. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ import {createResource} from 'simple-cache-provider'; async function searchMovies(query) { const response = await fetch(/* URL */); return await response.json(); } const readMovieSearchResults = createResource(searchMovies); function Results(/* args */) { // ... const {results} = readMovieSearchResults(cache, query); return ( <div> {results.slice(0, 5).map(result => { return ( <Result result={result} // ... /> ); })} </div> ); }
  11. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ import {createResource} from 'simple-cache-provider'; async function searchMovies(query) { const response = await fetch(/* URL */); return await response.json(); } const readMovieSearchResults = createResource(searchMovies); function Results(/* args */) { // ... const {results} = readMovieSearchResults(cache, query); return ( <div> {results.slice(0, 5).map(result => { return ( <Result result={result} // ... /> ); })} </div> ); }
  12. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ import {createResource} from 'simple-cache-provider'; async function searchMovies(query) { const response = await fetch(/* URL */); return await response.json(); } const readMovieSearchResults = createResource(searchMovies); function Results(/* args */) { // ... const {results} = readMovieSearchResults(cache, query); return ( <div> {results.slice(0, 5).map(result => { return ( <Result result={result} // ... /> ); })} </div> ); }
  13. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ import {createResource} from 'simple-cache-provider'; async function searchMovies(query) { const response = await fetch(/* URL */); return await response.json(); } const readMovieSearchResults = createResource(searchMovies); function Results(/* args */) { // ... const {results} = readMovieSearchResults(cache, query); return ( <div> {results.slice(0, 5).map(result => { return ( <Result result={result} // ... /> ); })} </div> ); }
  14. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ import {createResource} from 'simple-cache-provider'; async function searchMovies(query) { const response = await fetch(/* URL */); return await response.json(); } const readMovieSearchResults = createResource(searchMovies); function Results(/* args */) { // ... const {results} = readMovieSearchResults(cache, query); return ( <div> {results.slice(0, 5).map(result => { return ( <Result result={result} // ... /> ); })} </div> ); } ͜͜ͰDBDIF͔Βऔͬͯ͘Δ
  15. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ import {createResource} from 'simple-cache-provider'; async function searchMovies(query) { const response = await fetch(/* URL */); return await response.json(); } const readMovieSearchResults = createResource(searchMovies); function Results(/* args */) { // ... const {results} = readMovieSearchResults(cache, query); return ( <div> {results.slice(0, 5).map(result => { return ( <Result result={result} // ... /> ); })} </div> ); } DBDIF͕ͳ͔ͬͨΒUISPXOFX1SPNJTF
  16. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ let cachedResults = null; const readMovieSearchResults = ({query}) => { if (cachedResults) { return cachedResults; } throw new Promise(async resolve => { const results = await searchMovies(query); cachedResults = results; resolve(); }); }; TJNQMFDBDIFQSPWJEFS͕ͳ͔ͬͨΒ͜Μͳײ͡ʹͳΔ͸ͣ
  17. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ let cachedResults = null; const readMovieSearchResults = ({query}) => { if (cachedResults) { return cachedResults; } throw new Promise(async resolve => { const results = await searchMovies(query); cachedResults = results; resolve(); }); }; TJNQMFDBDIFQSPWJEFS͕ͳ͔ͬͨΒ͜Μͳײ͡ʹͳΔ͸ͣ
  18. ©2018 Wantedly, Inc. React Suspense TJNQMFDBDIFQSPWJEFS ‣ DBDIFΛ͍ͯ͠Δͱ͜Ζͷ࣮૷ ‣ GBDFCPPLSFBDUʹೖ͍ͬͯΔ

    ‣ ໊લͱ͔࣮૷ͱ͔͸มΘΔ͔΋ let cachedResults = null; const readMovieSearchResults = ({query}) => { if (cachedResults) { return cachedResults; } throw new Promise(async resolve => { const results = await searchMovies(query); cachedResults = results; resolve(); }); }; TJNQMFDBDIFQSPWJEFS͕ͳ͔ͬͨΒ͜Μͳײ͡ʹͳΔ͸ͣ
  19. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTF DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  20. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTF DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  21. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTF DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  22. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTF DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  23. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTF
 DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  24. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTF
 DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  25. ©2018 Wantedly, Inc. React Suspense 3FBDU5JNFPVU ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘

    ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣ UISPXΛDBUDIͨ͠Βɺ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTFɻ DIJMESFO͕SFOEFS͞ΕΔ import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  26. ©2018 Wantedly, Inc. ‣ ·ͣEJE5JNFPVUGBMTFͰݺͼग़͞ΕΔ ‣ DIJMESFO͕SFOEFS͞ΕΔͱDBDIFݟʹߦ͘ ‣ ଘࡏ͠ͳ͍ͱ͖͸ɺ1SPNJTF͕UISPX͞ΕΔ ‣

    UISPXΛDBUDIͨ͠ΒɺNT଴ͬͯ΋͏Ұ౓࣮ߦ ‣ EJE5JNFPVUUSVFͱͳͬͯɺGBMMCBDL͕දࣔ͞ΕΔ ‣ 1SPNJTF͕SFTPMWF͢ΔͱEJE5JNFPVUGBMTFɻ DIJMESFO͕SFOEFS͞ΕΔ React Suspense 3FBDU5JNFPVU import React, {Fragment} from 'react'; function Timeout({ms, fallback, children}) { return ( <React.Timeout ms={ms}> {didTimeout => ( <Fragment> <span hidden={didTimeout}>{children}</span> {didTimeout ? fallback : null} </Fragment> )} </React.Timeout> ); } export default Timeout;
  27. ©2018 Wantedly, Inc. React Suspense on Apollo "TZOD.PEF const Photo

    = ({ breed }) => ( <Query suspend query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data }) => { return <Image src={data.dog.displayImage} />; }} </Query> ); ‣ ͳΜͯݺͿ͔͸Θ͔Βͳ͍ ‣ ࠷ॳ͸QSPQTͷ໊લ͕"TZD.PEFͩͬͨ ‣ 3FBDU"QPMMPͰϦϦʔε͢ΔΒ͍͠ ‣ "QPMMP$MJFOUͷ2VFSZ .VUBUJPOίϯ ϙʔωϯτͰ؆୯ʹඇಉظϨϯμϦϯά͕ Ͱ͖Δ
  28. ©2018 Wantedly, Inc. React Suspense on Apollo const Photo =

    ({ breed }) => ( <Query suspend query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data }) => { return <Image src={data.dog.displayImage} />; }} </Query> ); ‣ ͳΜͯݺͿ͔͸Θ͔Βͳ͍ ‣ ࠷ॳ͸QSPQTͷ໊લ͕"TZD.PEFͩͬͨ ‣ 3FBDU"QPMMPͰϦϦʔε͢ΔΒ͍͠ ‣ "QPMMP$MJFOUͷ2VFSZ .VUBUJPOίϯ ϙʔωϯτͰ؆୯ʹඇಉظϨϯμϦϯά͕ Ͱ͖Δ "TZOD.PEF
  29. ©2018 Wantedly, Inc. React Suspense on Apollo const Photo =

    ({ breed }) => ( <Query suspend query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data }) => { return <Image src={data.dog.displayImage} />; }} </Query> ); const Photo = ({ breed }) => ( <Query query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data, loading }) => { if (loading) return <Loading /> return <Image src={data.dog.displayImage} />; }} </Query> ); ‣ ͳΜͯݺͿ͔͸Θ͔Βͳ͍ ‣ ࠷ॳ͸QSPQTͷ໊લ͕"TZD.PEFͩͬͨ ‣ 3FBDU"QPMMPͰϦϦʔε͢ΔΒ͍͠ ‣ "QPMMP$MJFOUͷ2VFSZ .VUBUJPOίϯ ϙʔωϯτͰ؆୯ʹඇಉظϨϯμϦϯά͕ Ͱ͖Δ "TZOD.PEF
  30. ©2018 Wantedly, Inc. React Suspense on Apollo const Photo =

    ({ breed }) => ( <Query suspend query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data }) => { return <Image src={data.dog.displayImage} />; }} </Query> ); const Photo = ({ breed }) => ( <Query query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data, loading }) => { if (loading) return <Loading /> return <Image src={data.dog.displayImage} />; }} </Query> ); ‣ ͳΜͯݺͿ͔͸Θ͔Βͳ͍ ‣ ࠷ॳ͸QSPQTͷ໊લ͕"TZD.PEFͩͬͨ ‣ 3FBDU"QPMMPͰϦϦʔε͢ΔΒ͍͠ ‣ "QPMMP$MJFOUͷ2VFSZ .VUBUJPOίϯ ϙʔωϯτͰ؆୯ʹඇಉظϨϯμϦϯά͕ Ͱ͖Δ "TZOD.PEF
  31. ©2018 Wantedly, Inc. React Suspense on Apollo const Photo =

    ({ breed }) => ( <Query suspend query={GET_DOG_PHOTO} variables={breed && { breed }}> {({ data }) => { return <Image src={data.dog.displayImage} />; }} </Query> ); <Timeout ms={2000}> {expired => expired && selectedDog ? ( <Loading /> ) : ( <Photo breed={selectedDog} /> ) } </Timeout> ‣ ͳΜͯݺͿ͔͸Θ͔Βͳ͍ ‣ ࠷ॳ͸QSPQTͷ໊લ͕"TZD.PEFͩͬͨ ‣ 3FBDU"QPMMPͰϦϦʔε͢ΔΒ͍͠ ‣ "QPMMP$MJFOUͷ2VFSZ .VUBUJPOίϯ ϙʔωϯτͰ؆୯ʹඇಉظϨϯμϦϯά͕ Ͱ͖Δ "TZOD.PEF
  32. ©2018 Wantedly, Inc. React Suspense on Apollo Ͳ͏΍࣮ͬͯ૷͞Ε͍ͯΔ͔ class Query

    extends React.Component { // ... render() { return this.props.children(this.getQueryResult(this.state)); } //... } private getQueryResult = ({queryObservable, evictData}) => { const currentResult = queryObservable!.currentResult(); const { loading, networkStatus, errors } = currentResult; if (loading) { if (this.props.suspend) { throw this.state.queryObservable!.result(); } Object.assign(data.data, this.previousData, currentResult.data); } else if (error) { // ... }; ‣ SFOEFSͷதͰHFU2VFSZ3FTVMU͕ݺ͹Ε͍ͯΔ ‣ ͦͷதͰMPEJOHTVTQFOEͩͬͨΒ
 1SPNJTFΛUISPX
  33. ©2018 Wantedly, Inc. React Suspense on Apollo Ͳ͏΍࣮ͬͯ૷͞Ε͍ͯΔ͔ class Query

    extends React.Component { // ... render() { return this.props.children(this.getQueryResult(this.state)); } //... } private getQueryResult = ({queryObservable, evictData}) => { const currentResult = queryObservable!.currentResult(); const { loading, networkStatus, errors } = currentResult; if (loading) { if (this.props.suspend) { throw this.state.queryObservable!.result(); } Object.assign(data.data, this.previousData, currentResult.data); } else if (error) { // ... }; ‣ SFOEFSͷதͰHFU2VFSZ3FTVMU͕ݺ͹Ε͍ͯΔ ‣ ͦͷதͰMPEJOHTVTQFOEͩͬͨΒ
 1SPNJTFΛUISPX
  34. ©2018 Wantedly, Inc. React Suspense on Apollo Ͳ͏΍࣮ͬͯ૷͞Ε͍ͯΔ͔ class Query

    extends React.Component { // ... render() { return this.props.children(this.getQueryResult(this.state)); } //... } private getQueryResult = ({queryObservable, evictData}) => { const currentResult = queryObservable!.currentResult(); const { loading, networkStatus, errors } = currentResult; if (loading) { if (this.props.suspend) { throw this.state.queryObservable!.result(); } Object.assign(data.data, this.previousData, currentResult.data); } else if (error) { // ... }; ‣ SFOEFSͷதͰHFU2VFSZ3FTVMU͕ݺ͹Ε͍ͯΔ ‣ ͦͷதͰMPEJOHTVTQFOEͩͬͨΒ
 1SPNJTFΛUISPX
  35. ©2018 Wantedly, Inc. React Suspense on Apollo Ͳ͏΍࣮ͬͯ૷͞Ε͍ͯΔ͔ class Query

    extends React.Component { // ... render() { return this.props.children(this.getQueryResult(this.state)); } //... } private getQueryResult = ({queryObservable, evictData}) => { const currentResult = queryObservable!.currentResult(); const { loading, networkStatus, errors } = currentResult; if (loading) { if (this.props.suspend) { throw this.state.queryObservable!.result(); } Object.assign(data.data, this.previousData, currentResult.data); } else if (error) { // ... }; ‣ SFOEFSͷதͰHFU2VFSZ3FTVMU͕ݺ͹Ε͍ͯΔ ‣ ͦͷதͰMPEJOHTVTQFOEͩͬͨΒ
 1SPNJTFΛUISPX
  36. ©2018 Wantedly, Inc. React Suspense on Apollo Ͳ͏΍࣮ͬͯ૷͞Ε͍ͯΔ͔ class Query

    extends React.Component { // ... render() { return this.props.children(this.getQueryResult(this.state)); } //... } private getQueryResult = ({queryObservable, evictData}) => { const currentResult = queryObservable!.currentResult(); const { loading, networkStatus, errors } = currentResult; if (loading) { if (this.props.suspend) { throw this.state.queryObservable!.result(); } Object.assign(data.data, this.previousData, currentResult.data); } else if (error) { // ... }; ‣ SFOEFSͷதͰHFU2VFSZ3FTVMU͕ݺ͹Ε͍ͯΔ ‣ ͦͷதͰMPEJOHTVTQFOEͩͬͨΒ
 1SPNJTFΛUISPX