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

Hooks時代の設計の話 #agrinoteinside

Hooks時代の設計の話 #agrinoteinside

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

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

Avatar for Yukiya Nakagawa

Yukiya Nakagawa

June 25, 2020
Tweet

More Decks by Yukiya Nakagawa

Other Decks in Technology

Transcript

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

    ڽू౓ɾ݁߹౓ʹӨڹ͢ΔϑοΫɺ͠ͳ͍ϑοΫ • ڽू౓ɾ݁߹౓͕ѱ͘ͳΔϑοΫΛͲ͏ѻ͏͔ • StorybookΛ࢖͍͍ͨ৔߹͸΋͏Ұखؒ 3
  2. 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
  3. Better const FatController = () => { return ( <View>

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

    <View> <View> <Text>{hoge}</Text> <Text>{fuga}</Text> <Text>{piyo}</Text> </View> </View> ) }; UIʹؔ৺ͷ͋Δॲཧ͔͠ѻ Θͳ͍ΧελϜϑοΫʹ͢ ΂ͯΛ௥͍ग़͢ ࠷ऴతʹදࣔ͢Δσʔλͱߋ৽ํ๏ͷΈΛఏڙ͢Δ ΧελϜϑοΫͷݺͼग़͠ɿߦ ΫϦοΫΠϕϯτͷड͚औΓʢ6*ͷؔ৺ʣɿߦ +49͸6*ͷؔ৺ 17
  5. 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
  6. ϑοΫ͸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
  7. ঢ়ଶΛѻ͏ϑοΫ ʢ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
  8. ڽू౓ɾ݁߹౓΁ͷӨڹ • Ͳ͜ͷ֊૚ͷίϯϙʔωϯτʹஔ͍ͯ΋ڽू౓ɾ݁߹౓ʹ΄΅Өڹ͠ͳ͍ • ϝϞԽΛѻ͏ϑοΫ • खଓ͖తϓϩάϥϛϯάΛѻ͏ϑοΫ • ಈ࡞ʹӨڹ͠ͳ͍ϑοΫ •

    ڽू౓ɾ݁߹౓ʹμΠϨΫτʹӨڹ͢Δ • ঢ়ଶΛѻ͏ϑοΫʢσʔλʹؔ৺͕͋Δʣ • ෭࡞༻Λѻ͏ϑοΫʢ෭࡞༻Ͱ֎քʹܨ͕Γ͕ͪʣ • ঢ়ଶΛ఻೻͢ΔϑοΫʢ֎ք͔ΒσʔλΛྲྀ͠ࠐΉʣ 23
  9. ڽू౓ɾ݁߹౓ʹӨڹ͕͋ΔϑοΫΛͲ͏ѻ͏͔ • Ͱ͖Δ্͚ͩҐͷίϯϙʔωϯτͰར༻ͨ͠΄͏͕Α͍ • Atomic DesignͰ͍͏ͱ͜ΖͷOrganisms͘Β͍ͷ৔ॴͰ࢖͏Α͏ʹҙࣝ͢ΔͱΑ͍ • Molecules΍AtomsͰ΋ɺίϯϙʔωϯτͷ֎ଆʹӨڹΛٴ΅͞ͳ͍΋ͷͳΒ͹OK • ֎քͱͷ઀ଓΛΧελϜϑοΫʹҰຊԽ͢Δ

    • Reactͷ֎ଆʢΠϯλʔωοτ΍Reduxʣͱ΍ΓͱΓ͢ΔॲཧΛΧελϜϑοΫʹ·ͱΊ Δͱɺίϯϙʔωϯτͱͷ݁߹౓Λ࠷௿ݶʹ཈͑Δ͜ͱ͕Ͱ͖Δ • ࣗ࡞ͷΧελϜϑοΫ͚ͩͰ͸ͳ͘ɺαʔυύʔςΟͷΧελϜϑοΫʢuseQuery, useSWR, useFetch, useSelectorͳͲͳͲʣΛ௚઀ίϯϙʔωϯτʹઃஔͯ͠΋Α͍ ϖΠϯ୯Ґ͘Β͍ʹͳΔΜ͡Όͳ͍͔ͳͱ 26
  10. Presentational and Container Components • 2015೥ͷهࣄ͕ॳग़*1 • 2019೥ͷDan Abramov͸ʮίʔυϕʔε্͜ͷ෼཭Λߦ͏͜ͱ͕ࣗવͰ͋Ε͹ ศརʹ࢖͑Δ͚Ͳɺͦ͏Ͱͳ͍ͳΒ͜ͷ෼཭ํ๏ΛӏವΈʹ͢Δͷ͸΍Ίͨ΄͏

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

    ৼΔ෣͍Λఆٛ͢Δ 3FBDUͷ֎ଆΛ ஌Βͳ͍ ஌͍ͬͯΔ 4UPSZCPPLͰ දࣔͰ͖Δ දࣔͰ͖ͳ͍͜ͱ͕ଟ͍ 30
  12. 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