Hooks時代の設計の話 #agrinoteinside

Hooks時代の設計の話 #agrinoteinside

ウォーターセル株式会社の社内勉強会 https://water-cell.connpass.com/event/178648/ で発表したものです。

YouTube Liveアーカイブはこちら
https://youtu.be/ZLUie-ndKgw

9a6e4623f9314c5e1fc99635ac9617ed?s=128

Yukiya Nakagawa

June 25, 2020
Tweet

Transcript

  1. Hooks࣌୅ͷઃܭͷ࿩ React Hooksษڧձ #6 2020.6.25 Yukiya Nakagawa a.k.a Nkzn 1

  2. Yukiya Nakagawa ΢Υʔλʔηϧࣾһ൪߸3൪ ϞόΠϧΤϯδχΞ ٕज़ॻయWebΛReact.FCͱHooksͰ ϦϓϨΠεͨ͠ओ൜ 2

  3. ΞδΣϯμ • ࠓճݴٴ͢Δʮઃܭʯ • Fat Controller͔Βߟ͑Δڽू౓ͱ݁߹౓ • React Hooksͱڽू౓ɾ݁߹౓ •

    ڽू౓ɾ݁߹౓ʹӨڹ͢ΔϑοΫɺ͠ͳ͍ϑοΫ • ڽू౓ɾ݁߹౓͕ѱ͘ͳΔϑοΫΛͲ͏ѻ͏͔ • StorybookΛ࢖͍͍ͨ৔߹͸΋͏Ұखؒ 3
  4. ࠓճݴٴ͢Δʮઃܭʯ • ઃܭͱ͸ݱ࣮ੈքͷ՝୊Λղܾ͢ΔͨΊʹ1ͭ·ͨ͸ز͔ͭͷ؍఺͔ Βଥ౰ͳࢪࡦΛݕ౼ɾܾఆ͢Δ͜ͱʢཁग़యʣ • ϑΝΠϧ΍ϑΥϧμ΍Ҿ਺ͷ্खͳ੔ཧͷ࢓ํ͸ɺઃܭͰ͸ͳ͘ߏ଄ ͱݺ͹ΕΔ෼໺ • ͲΜͳ՝୊Λղܾ͢ΔͨΊʹɺͲΜͳ؍఺Ͱߏ଄ΛܾΊ͍͔ͯ͘ •

    React Hooks͕ੜΈग़͢ߏ଄͸ɺڽू౓ͱ݁߹౓ͷ՝୊Λղܾ͠΍͢ ͍ʢؾ͕͢ΔʣͷͰɺࠓճ͸ڽू౓ͱ݁߹౓ͷ࿩Λ͠·͢ 4
  5. Fat Controller͔Βߟ͑Δ ڽू౓ͱ݁߹౓ 5

  6. GUIϑϨʔϜϫʔΫͷӬԕͷ՝୊ • Fat Controller • UIͷݟͨ໨Λ௚઀ѻ͑ΔείʔϓʹɺશͯͷϩδοΫΛॻ͘ελΠϧ • Reactͷؔ਺ίϯϙʔωϯτͰ͍͏ͱɺreturnͷ্ 6

  7. React Component as a Fat Controller const FatController = ()

    => { return ( <View> <View> <Text>{hoge}</Text> <Text>{fuga}</Text> <Text>{piyo}</Text> </View> </View> ) }; ෳ਺ͷؔ৺ʹର͢Δॲཧ͕ ίϯϙʔωϯτʹϕλॻ͖ ͞Ε͍ͯΔঢ়ଶ ࠷ऴతʹදࣔ͢Δσʔλͷ؅ཧʢ6*ͷؔ৺ʣߦ ΫϦοΫΠϕϯτͷड͚औΓʢ6*ͷؔ৺ʣɿߦ ॳظԽ༻ͷ௨৴ʢ௨৴ͷؔ৺ʣߦ σʔλૹ৴༻ͷ௨৴ʢ௨৴ͷؔ৺ʣɿߦ +49͸6*ͷؔ৺ ௨৴݁ՌΛදࣔ༻σʔλʹՃ޻͢ΔʢՃ޻ͷؔ৺ʣɿߦ 7
  8. Fat ControllerͷԿ͕ѱ͍ͷ͔ • WebϑϩϯτΤϯυͰ͋Ε͹ɺ΄ͱΜͲͷॲཧ͸େผͯ͠ʮ௨৴ʯ ʮՃ޻ʯʮදࣔ/Πϕϯτड෇(UI)ʯͷͲΕ͔ͷؔ৺Λ࣋ͭ͜ͱ͕ଟ͍ • Fat ControllerͰ͸͜ΕΒͷॲཧ͕Ұಉʹհ͢Δ • ࠷ॳʹ࣮૷ͨ࣌͠఺Ͱ͸ಈ͘͠ɺ࣮૷ऀͷهԱʹ࿈ଓੑ͕͋ΔݶΓ͸

    ϝϯςͰ͖Δ ϏδωεϩδοΫΛؚΉ 8
  9. — Yukiya Nakagawa (1987- ) “͔࣮͠͠૷ऀ͸هԱΛࣦ͏” 9

  10. ໰୊఺ɿڽू౓͕௿͘ɺ݁߹౓͕ߴ͍ • ਺ඦߦʹ౉Δ༷ʑͳ໨తΛ࣋ͬͨॲཧͷதͰɺվमର৅ͷػೳʹ֘౰͢Δ ߦΛݟ͚ͭΔ࡞ۀ͸ࠔ೉ΛۃΊΔʢڽू౓͕௿͍ʣ • ͋Δ1ߦΛमਖ਼ͨ͠৔߹ͷӨڹൣғΛ஫ҙਂ֬͘ೝ͠ͳ͚Ε͹͍͚ͳ͍ʢ݁ ߹౓͕ߴ͍ʣ • ಛఆͷ਺ेߦ͔ΒͳΔҰ෦ͷػೳ͚ͩΛଞͷίϯϙʔωϯτͰ΋࠶ར༻͠ ͍ͨͱࢥͬͨ৔߹ʹɺͲͷߦΛൈ͖ग़ͤ͹͍͍͔Θ͔Βͳ͍ɺ͋Δ͍͸ί

    ϐϖ͢Δ͔͠ͳ͍ʢ݁߹౓͕ߴ͍ʣ 10
  11. ཧ૝͸͜Ε • ڽू౓͕ߴ͍ߏ଄ • ࣅͨ໨తͷॲཧ͕·ͱΊΒΕ͍ͯΔ • ݁߹౓͕௿͍ߏ଄ • ͋·Γؔ܎ͷͳ͍ॲཧಉ͕࢜ૄ݁߹Ͱ͋Δ 11

  12. ڽू౓͕ߴͯ݁͘߹౓͕௿͍ߏ଄ͮ͘Γ • ࣅͨ໨తͷॲཧΛಉ͡ϑΝΠϧ΍ϑΥϧμʹ·ͱΊͯɺ࢖͏ͱ͖͸౎౓Πϯϙʔτ͢Δ • ʮ௨৴ʯʮՃ޻ʯʮදࣔ/Πϕϯτड෇ʯ͸͢΂ͯผͷ໨తͷͨΊʹಈ͍͍ͯΔͷͰ ผϑΝΠϧʹ͢ΔͱΑ͍ • ʮ͜ͷछྨͷॲཧͳΒ͍͍ͩͨ͜ͷϑΥϧμΛݟʹ͍͚͹͋Δͳʯ͕Ͱ͖Δͷ͸͍͍͜ͱ • ʮ͜ͷϑΝΠϧΛमਖ਼ͯ͠΋յΕΔͷ͸͜ͷϑΝΠϧͷॲཧ͚ͩͩͳʯ͕Ͱ͖Δͷ΋͍͍͜ͱ

    • ES Modules͕࣮૷͞Εͯຊ౰ʹΑ͔ͬͨ (6*ΞϓϦέʔγϣϯͷϑΝΠϧɾϑΥϧμ੔ཧ͸͜Ε͕Ͱ͖Ε͹͍͍ͩͨউར 12
  13. Better const FatController = () => { return ( <View>

    <View> <Text>{hoge}</Text> <Text>{fuga}</Text> <Text>{piyo}</Text> </View> </View> ) }; UIҎ֎ͷॲཧͷৄࡉΛ ผϑΝΠϧʹ௥͍ग़͢ ڽू౓͸͔ͳΓ্͕ͬͨ ݁߹౓͸গ͠Լ͕͚ͬͨͩ Ͱ·ͩڧ͍ ࠷ऴతʹදࣔ͢Δσʔλͷ؅ཧʢ6*ͷؔ৺ʣߦ ΫϦοΫΠϕϯτͷड͚औΓʢ6*ͷؔ৺ʣɿߦ ॳظԽ༻ͷ௨৴ʢ௨৴ͷؔ৺ʣߦ ʢผϑΝΠϧͷϞδϡʔϧΛݺͼग़͚ͩ͢ʣ σʔλૹ৴༻ͷ௨৴ʢ௨৴ͷؔ৺ʣɿߦ ʢผϑΝΠϧͷϞδϡʔϧΛݺͼग़͚ͩ͢ʣ +49͸6*ͷؔ৺ ʢ௨৴ॲཧͷϞδϡʔϧ͔Βݺ͹Ε͍͚ͯͨͩͳͷͰফ໓ʣ 13
  14. React Hooksͱڽू౓ɾ݁߹౓ 14

  15. React.FCͷڽू౓ɾ݁߹౓͕ߴ͍ʁ௿͍ʁ • propsʹج͍ͮͨදࣔͷΈΛߦ͏ίϯϙʔωϯτʢ͍ΘΏΔPresentational Componentʣ͸ɺڽू౓͕ߴ͘ɺ݁߹౓͕௿͍ • ϑοΫΛ1ͭͰ΋࢖ͬͨίϯϙʔωϯτ͸ɺ݁߹౓͕গ্͕͠Δ • ωΨςΟϒͳ࿩Ͱ͸ͳ͘ɺࣗવͳ͜ͱͱͯ͠ • ڽू౓͕Լ͕Δ͔Ͳ͏͔͸৔߹ʹΑΔ

    • ϑοΫΛͨ͘͞Μॻ͘ͱɺͦΕͳΓʹڽू౓͕Լ͕ͬͨΓ݁߹౓্͕͕ͬͨΓ͢Δ • Fat Controller΁ͷಓ 15
  16. ΧελϜϑοΫ͸ྑ͍ӨڹΛٴ΅͢ • ॲཧΛΧελϜϑοΫʹ·ͱΊΔͱɺؔ਺ίϯϙʔωϯτ͔Β௚઀ѻ ͏ϑοΫͷ਺͕ݮΔͷͰɺ݁߹౓͕Լ͕Δ • ΧελϜϑοΫΛద੾ͳཻ౓ʹ·ͱΊΔ͜ͱ͕Ͱ͖Ε͹ɺڽू౓্͕ ͕Δ 16

  17. More Better const FatController = () => { return (

    <View> <View> <Text>{hoge}</Text> <Text>{fuga}</Text> <Text>{piyo}</Text> </View> </View> ) }; UIʹؔ৺ͷ͋Δॲཧ͔͠ѻ Θͳ͍ΧελϜϑοΫʹ͢ ΂ͯΛ௥͍ग़͢ ࠷ऴతʹදࣔ͢Δσʔλͱߋ৽ํ๏ͷΈΛఏڙ͢Δ ΧελϜϑοΫͷݺͼग़͠ɿߦ ΫϦοΫΠϕϯτͷड͚औΓʢ6*ͷؔ৺ʣɿߦ +49͸6*ͷؔ৺ 17
  18. Real World const Articles = () => { const {

    data, loading, error } = useArticlesService(); if (loading) { return <Loading /> } if (error) { return <Error error={error} /> } if (!data?.articles) { return <NoData /> } return ( <> {props.articles.map(article => ( <View> <Text>title: {article.title}</Text> <View> <Text>summary:</Text> <Text>{article.summary}</Text> </View> </View> ))} </> ); }; ݟͨ͘ͳ͍΋ͷ͸Ӆṭ͢Δ ΧελϜϑοΫͷத͸FatͰ ΋Α͍ʢFat Model͸OKʣ GraphQL + Apollo ClientΛ࢖͍ͬͯΔͱΧελϜϑοΫͷ୅Θ ΓʹuseQueryͰ΋ߦ͚ͨΓ͢Δ ʢ௨৴ͷӅṭ͕Ͱ͖͍ͯΔˍՃ޻ॲཧ͕ݮΔ܏޲ʹ͋ΔͨΊʣ 'BUʹͳΔཁҼΛ ΧελϜϑοΫʹด͡ࠐΊΔ 18
  19. ڽू౓ɾ݁߹౓ʹ Өڹ͢ΔϑοΫɺ͠ͳ͍ϑοΫ 19

  20. ϑοΫ͸10छྨ͔͠ͳ͍ • ͍ΖΜͳΧελϜϑοΫΛோΊ͍ͯΔͱ๨Εͦ͏ʹͳΔΜ͚ͩͲɺVirtual DOMͷࠩ෼ݕ ग़ॲཧΛ࢘Δreact-reconcilerʢௐ࿨Λ΋ͨΒ͢ऀʣͱ௚݁ͨ͠ʮຊ෺ͷʯϑοΫ͸10छྨ ͔͠ͳ͍ • ࣮͸masterΛݟʹߦ͘ͱɺConcurrent ModeͳͲͷབྷΈͰ15ݸʹ૿͍͑ͯΔ*1Μ͚ͩ Ͳɺͻͱ·ͣݟͳ͔ͬͨ͜ͱʹͯ͠ཉ͍͠

    • ૿͑ͨ෼ʹڵຯ͕͋Δਓ͸Concurrent ModeͷυΩϡϝϯτ*2ΛಡΜͰ΄͍͠ 1. https://github.com/facebook/react/blob/30b47103d4354d9187dc0f1fb804855a5208ca9f/packages/react-reconciler/src/ReactFiberHooks.new.js#L110-L124 2. https://ja.reactjs.org/docs/concurrent-mode-patterns.html 20
  21. ϑοΫ͸10छྨ͔͠ͳ͍ • υΩϡϝϯτ্͸ʮجຊͷϑοΫʯʮ௥ՃͷϑοΫʯͱ͍͏࢖༻ස౓ʁʹΑΔ෼ྨ͕ߦΘ Ε͍ͯΔ͚Ͳɺઃܭ্͸΋͏গ͠ผͷ੾ΓޱͰ෼ྨͯ͠ೝ͓͍ࣝͯͨ͠΄͏͕ྑ͍ 21

  22. ঢ়ଶΛѻ͏ϑοΫ ʢ7%0.ߋ৽ͷى఺ʹͳΕΔͷ͸ࣄ্࣮͜Ε͚ͩʣ w VTF4UBUF w VTF3FEVDFS ঢ়ଶΛ఻೻͢ΔϑοΫ w VTF$POUFYU ෭࡞༻Λѻ͏ϑοΫ

    w VTF&⒎FDU w VTF-BZPVU&⒎FDU ϝϞԽΛѻ͏ϑοΫ w VTF$BMMCBDL w VTF.FNP खଓ͖తϓϩάϥϛϯάΛѻ͏ϑοΫ w VTF3FG w VTF*NQFSBUJWF)BOEMF ಈ࡞ʹӨڹ͠ͳ͍ϑοΫ w VTF%FCVH7BMVF 22
  23. ڽू౓ɾ݁߹౓΁ͷӨڹ • Ͳ͜ͷ֊૚ͷίϯϙʔωϯτʹஔ͍ͯ΋ڽू౓ɾ݁߹౓ʹ΄΅Өڹ͠ͳ͍ • ϝϞԽΛѻ͏ϑοΫ • खଓ͖తϓϩάϥϛϯάΛѻ͏ϑοΫ • ಈ࡞ʹӨڹ͠ͳ͍ϑοΫ •

    ڽू౓ɾ݁߹౓ʹμΠϨΫτʹӨڹ͢Δ • ঢ়ଶΛѻ͏ϑοΫʢσʔλʹؔ৺͕͋Δʣ • ෭࡞༻Λѻ͏ϑοΫʢ෭࡞༻Ͱ֎քʹܨ͕Γ͕ͪʣ • ঢ়ଶΛ఻೻͢ΔϑοΫʢ֎ք͔ΒσʔλΛྲྀ͠ࠐΉʣ 23
  24. ஫ҙ͢΂͖΋ͷ͸3෼ྨ͚ͩ • ঢ়ଶΛѻ͏ϑοΫʢ㲈 useStateʣ • ෭࡞༻Λѻ͏ϑοΫʢ㲈 useEffectʣ • ঢ়ଶΛ఻೻͢ΔϑοΫʢ㲈 useContextʣ

    جຊͷϑοΫͩʜʜʂʁ 24
  25. ڽू౓ɾ݁߹౓ʹӨڹ͕͋Δ ϑοΫΛͲ͏ѻ͏͔ 25

  26. ڽू౓ɾ݁߹౓ʹӨڹ͕͋ΔϑοΫΛͲ͏ѻ͏͔ • Ͱ͖Δ্͚ͩҐͷίϯϙʔωϯτͰར༻ͨ͠΄͏͕Α͍ • Atomic DesignͰ͍͏ͱ͜ΖͷOrganisms͘Β͍ͷ৔ॴͰ࢖͏Α͏ʹҙࣝ͢ΔͱΑ͍ • Molecules΍AtomsͰ΋ɺίϯϙʔωϯτͷ֎ଆʹӨڹΛٴ΅͞ͳ͍΋ͷͳΒ͹OK • ֎քͱͷ઀ଓΛΧελϜϑοΫʹҰຊԽ͢Δ

    • Reactͷ֎ଆʢΠϯλʔωοτ΍Reduxʣͱ΍ΓͱΓ͢ΔॲཧΛΧελϜϑοΫʹ·ͱΊ Δͱɺίϯϙʔωϯτͱͷ݁߹౓Λ࠷௿ݶʹ཈͑Δ͜ͱ͕Ͱ͖Δ • ࣗ࡞ͷΧελϜϑοΫ͚ͩͰ͸ͳ͘ɺαʔυύʔςΟͷΧελϜϑοΫʢuseQuery, useSWR, useFetch, useSelectorͳͲͳͲʣΛ௚઀ίϯϙʔωϯτʹઃஔͯ͠΋Α͍ ϖΠϯ୯Ґ͘Β͍ʹͳΔΜ͡Όͳ͍͔ͳͱ 26
  27. StorybookΛ࢖͍͍ͨ৔߹͸΋͏Ұखؒ 27

  28. Storybook + React Hooks͋Δ͋Δ • ֎ք͕བྷΉίϯϙʔωϯτ͸StorybookͰಈ͔ͮ͠Β͍ • ೝূ͕ඞཁͳ௨৴Λ൐͏useEffect΍ΧελϜϑοΫ͕ઃஔ͞Ε͍ͯΔ ৔߹͕ಛʹਏ͍ •

    ֎քͱͷ݁߹౓Λθϩʹͨ͠ίϯϙʔωϯτ͚͕ͩଘࡏΛڐ͞ΕΔ • ྫ֎తʹ<ThemeProvider>ͱͷີ݁߹͸ڐ͞ΕΔ 28
  29. Presentational and Container Components • 2015೥ͷهࣄ͕ॳग़*1 • 2019೥ͷDan Abramov͸ʮίʔυϕʔε্͜ͷ෼཭Λߦ͏͜ͱ͕ࣗવͰ͋Ε͹ ศརʹ࢖͑Δ͚Ͳɺͦ͏Ͱͳ͍ͳΒ͜ͷ෼཭ํ๏ΛӏವΈʹ͢Δͷ͸΍Ίͨ΄͏

    ͕͍͍ɻෳࡶͳϩδοΫΛ෼཭͍͚ͨͩ͠Ͱ͋Ε͹ɺϑοΫΛ࢖͑͹ίϯϙʔω ϯτΛΘ͟Θ͟෼཭͢Δඞཁ΋ͳ͍͔ΒͰ͢ʯͱݴ͍ͬͯΔ • େͯ͠ෳࡶͳϩδοΫ΋͍࣋ͬͯͳ͍ͷʹɺ೴ࢮͰContainerΛ੾Γग़͍ͯ͠Δϓ ϩδΣΫτΛ͔ͦ͜͜͠Ͱݟ͔͚ͯݏʹͳͬͨΒ͍͠ • ͱ͸͍͑༗ޮͳͱ͖͸༗ޮͳͷͰɺྫྷ੩ʹ࢖͍͖͍ͬͯͨ 1. https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 29
  30. Presentational and Container Components 1SFTFOUBUJPOBM $PNQPOFOUT $POUBJOFS $PNQPOFOUT ༻్ ݟͨ໨Λఆٛ͢Δ

    ৼΔ෣͍Λఆٛ͢Δ 3FBDUͷ֎ଆΛ ஌Βͳ͍ ஌͍ͬͯΔ 4UPSZCPPLͰ දࣔͰ͖Δ දࣔͰ͖ͳ͍͜ͱ͕ଟ͍ 30
  31. StorybookΛ࢖͍͍ͨ৔߹͸΋͏Ұखؒ • Container͸ʮReactͰ͸ͳ͍ੈքͱͷڥքʯͱͯ͠ಇ͘ • ֎քͱͷ૭ޱʹͳΔΧελϜϑοΫ͸Container Componentsʹઃஔ ͢ΔͱΑ͍ 31

  32. Presentational and Container Components // src/components/articles.js export const ArticlesComponent =

    (props) => ( <> {props.articles.map(article => ( <View> <Text>title: {article.title}</Text> <View> <Text>summary:</Text> <Text>{article.summary}</Text> </View> </View> ))} </> ); // src/containers/articles.js export const Articles = () => { const { data, loading, error } = useArticlesService(); useErrorHandler(error); if (loading) { return <Loading /> } if (!data?.articles) { return <NoData /> } return <ArticlesComponent data={articles} /> }; ContainerଆʹʢΧελϜʣ ϑοΫΛઃஔ͢Δ͜ͱͰɺ Presentationalଆ͔Β֎ք΁ ͷ݁߹౓ΛԼ͛Δ ֎քͱͷ΍ΓͱΓ͸ $POUBJOFSʹ೚ͤΔ ඇಉظঢ়ଶͷ؅ཧ΍ ΤϥʔϋϯυϦϯάΛͲ͜Ͱ΍Δ͔͸ ٞ࿦ͷ༨஍͕͋Γͦ͏ 1SFTFOUBUJPOBM͸ ݟͨ໨ͷఆٛʹઐ೦͢Δ 32
  33. ͓͠·͍