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

redux-pluto

 redux-pluto

Folio Scramble! #1 で話した redux best practiceの話です。

D76231a2114896dfcc7b79ac69558b79?s=128

Yosuke Furukawa
PRO

April 19, 2018
Tweet

Transcript

  1. redux-pluto 2018/04/19 @ Folio Meetup # Scramble! #1

  2. Twitter: @yosuke_furukawa Github: yosuke-furukawa

  3. redux-pluto • ϦΫϧʔτςΫϊϩδʔζࣾͰ։ൃதͷϘΠϥʔϓ Ϩʔτ • େن໛։ൃ޲͚ɺϕετϓϥΫςΟεΛूΊͨ΋ ͷ • ͪͳΈʹ·ͩ։ൃதͳͷͰࠓ೔͸ϦϙδτϦ͸ެ ։Ͱ͖ͳ͍Ͱ͢ɺӶҙקΊதͰ͢ɻ


    ͍͢·ͤΜɺɺɺ
  4. redux-pluto • ϦΫϧʔτςΫϊϩδʔζࣾͰ։ൃதͷϘΠϥʔϓ Ϩʔτ • େن໛։ൃ޲͚ɺϕετϓϥΫςΟεΛूΊͨ΋ ͷ • ͪͳΈʹ·ͩ։ൃதͳͷͰࠓ೔͸ϦϙδτϦ͸ެ ։Ͱ͖ͳ͍Ͱ͢ɺӶҙקΊதͰ͢ɻ


    ͍͢·ͤΜɺɺɺ ࠓ೔͸͜ͷϕετϓϥΫςΟεΛ νϥݟͤ
  5. ϕετϓϥΫςΟε ΞʔΩςΫνϟฤ

  6. ϕετϓϥΫςΟε 1
 ඇಉظσʔλϩʔυ

  7. ඇಉظσʔλϩʔυ • redux-async-loader • SSRͰ΋CSRͰ΋ಈ͘σʔλFetchؔ਺Λఏڙ ͯ͘͠ΕΔ • σʔλFetchத͸ReactͷrenderΛ͠ͳ͍࡞Γ

  8. ඇಉظσʔλϩʔυ • redux-async-loader import { compose } from 'recompose'; export

    default compose( // CSR Ͱ΋ SSR Ͱ΋྆ํಈ͘ // σʔλ͕ϩʔυ͞ΕͯΔͱloading state͕trueʹͳΓɺͦͷظؒ͸ // component͕render͞Εͳ͍ɻ asyncLoader((props, { dispatch }) => dispatch(loadUsers(props))), connect({ ... }, { ... }) )(class UserList exptends React.Component { // ... });
  9. ඇಉظσʔλϩʔυ • ଞͷOSSࣄྫ • CyberAgent: https://github.com/kouhin/redux- dataloader • Next.js: getInitialProps

    https://github.com/zeit/ next.js/blob/master/examples/with-redux/pages/ index.js#L8-L13 • Nuxt.js: asyncData
  10. ඇಉظσʔλϩʔυ • Ͳͷํ๏Ͱ΋͍͍ͩͨಉ͕ͩ͡ɺredux-async- loader͸Ͳ͜ͷίϯϙʔωϯτ͔ΒͰ΋ඇಉظ σʔλϩʔυͰ͖Δɻ • Next.js, Nuxt.js ͷ΋ͷ͸RootͰͷΈൃՐՄೳ •

    େن໛։ൃͩͱ్தͷComponent͔ΒͰ΋ඇಉ ظϩʔυͰ͖Δํ͕خ͍͜͠ͱ΋ɻ
  11. ϕετϓϥΫςΟε 2
 reduxϑϩʔ੍ޚ

  12. reduxϑϩʔ੍ޚ • redux-effects-steps
 https://github.com/recruit-tech/redux-effects-steps • redux-thunk΍sagaɺObservableͱ͍͏खஈ͕͋Δ ͕ͦΕΒ͸࢖ͬͯͳ͍ɻ • ϑϩʔ੍ޚͰෳࡶͳॲཧΛॻ͚ΔΑ͏ʹͨ͘͠ͳ͍ •

    ෳࡶʹͳͬͯ͠·͏ͷͰ͋Ε͹middlewareʹಀ͕͢
  13. reduxϑϩʔ੍ޚ • redux-effects-steps
 https://github.com/recruit-tech/redux-effects-steps • import { createAction } from

    'redux-actions'; import { steps } from 'redux-effects-steps'; import { fetchrRead } from 'redux-effects-fetchr'; const fetchUserRequest = createAction('FETCH_USER_REQUEST'); const fetchUserSuccess = createAction('FETCH_USER_SUCCESS'); const fetchUserFail = createAction('FETCH_USER_FAIL'); function fetchUser({ user }) { return steps(
 // ϦΫΤετͨ͠ΒϦΫΤετͨ͜͠ͱΛActionͰൃՐ͓ͤͯ͘͞ɻ fetchUserRequest(), // ຊϦΫΤετ fetch ॲཧ fetchrRead('users', { user }),
 // ੒ޭͨ͠ΒSuccess Action, ࣦഊͨ͠Β Failure Action [fetchUserSuccess, fetchUserFail] ); }
  14. reduxϑϩʔ੍ޚ • ଞͷOSSࣄྫ • redux-thunk • redux-saga • redux-observable

  15. reduxϑϩʔ੍ޚ • redux-thunk͸ԿͰ΋Ͱ͖͗͢ΔɺActionΛॻ͘ॴͰࡉ͔͍ॲ ཧ͕ॻ͚Δͷ͸΍Γա͗ײ͋Δɻ͕ͦ͜Ԛ͘ͳΓͦ͏ɻ • redux-saga͸sagaͱ͍͏ϨΠϠͰόοΫάϥ΢ϯυϓϩηε తʹԿͰ΋΍Δɻ͜͜·Ͱͷॲཧ͕ඞཁʹͳͬͨέʔε͕গͳ ͍ɺΑ͋͘Δͷ͸ϦΫΤετΛൃՐͯͦ͠Ε͕੒ޭ͔ࣦͨ͠ഊ ͔ͨ͠ఔ౓ɺͦΕ͚ͩͰsaga͸ΦʔόʔΩϧײ •

    observable͸RxJSͰྲྀΕΛ੍ޚ͢Δͱ͍͏΋ͷ͕ͩɺͦ͜· Ͱͷྲྀྔ੍ݶ͕ඞཁʹͳͬͨ͜ͱ͕ͳ͍
  16. ϕετϓϥΫςΟε 3
 ducks

  17. ducks • https://github.com/erikras/ducks-modular- redux • reducer, actions, action creatorͱ͍͏ػೳͰ ෼͚ΔͷͰ͸ͳ͘ɺUserɺArticleͱ͍ͬͨΑ

    ͏ͳϦιʔεͷѻ͍Ͱ̍ͭͷϑΝΠϧʹ͢Δ
  18. ducks • https://github.com/erikras/ducks-modular- redux /* @flow */ /** * Initial

    State */ const SALON = "redux-proto/salon"; export const [ FIND_SALON_BY_ID_REQUEST, FIND_SALON_BY_ID_SUCCESS, FIND_SALON_BY_ID_FAIL ] = createAsyncActionTypes(`${SALON}/find_id`); /** * Action creators */ const findSalonByIdRequest = createAction(FIND_SALON_BY_ID_REQUEST); const findSalonByIdSuccess = createAction(FIND_SALON_BY_ID_SUCCESS); const findSalonByIdFail = createAction(FIND_SALON_BY_ID_FAIL);
  19. ducks • https://github.com/erikras/ducks-modular- redux /* @flow */ /** * Reducer

    */ export default (handleActions( { [FIND_SALON_BY_ID_REQUEST]: state => ({ … }), } )) /** * Selector */ export default (createSelector((state) => {…}, (items) => {…}))
  20. ducks • actions, action creator, reducer ͚ͩͰ͸ͳ͘ɺselector· Ͱதʹ࣋ͭɻ • ϑΝΠϧ͕େ͖͘ͳΓͦ͏ͳ࣌͸ϑΥϧμʹͯ͠ϑΝΠϧ

    ෼ׂ͢Δͷ΋༗Γɻ͜ͷล͸޷͖ʹ • re-ducksͱ͍͏΋ͷ΋͋Δ͕ɺ͜ΕͱͷϋΠϒϦουײɻ • ཁ͸΍Γ͍ͨͷ͸Ϧιʔε࣠Ͱ·ͱΊΔํ͕ػೳ࣠Ͱ·ͱ ΊΔΑΓ΋ॻ͖΍͘͢ɺݟ΍͔ͬͨ͢ɻ
  21. ϕετϓϥΫςΟε 4
 APIఆٛ

  22. APIఆٛ • agreed https://github.com/recruit-tech/ agreed • Consumer Driven ContractΛ࣮ફ •

    ϑϩϯτΤϯυ͕த৺ʹͳͬͯ։ൃΛ͢͢Ί Δ࢓૊Έʹͳ͍ͬͯΔɻ
  23. APIఆٛ • agreedͰAPIͷmockΛઌʹ࡞੒ • mockΛ࡞ΓऴΘͬͨΒAPI࡞੒ऀ(Server Side)ʹagreed-uiͰཁٻΛڞ༗ɻ • API͕ߏஙͰ͖͖ͯͨΒagreed-clientͰςετ έʔεͱ࣮ͯ͠ߦ͞ΕΔɻ

  24. APIఆٛ

  25. APIఆٛ • ଞOSSࣄྫ • Swagger • Pact

  26. APIఆٛ • Swagger͸APIͷ࢓༷ఆٛͰ͋ͬͯAPIͷཁٻ Ͱ͸ͳ͍ɻ͋͘·ͰυΩϡϝϯτɺmock΋࡞ ΕΔ͕࡞Γ΍͘͢͸ͳͦ͞͏ɻ • Pact͸clientͷςετσʔλ͔Βserverͷ νΣοΫΛ͢ΔͨΊͷσʔλΛࣗಈੜ੒͢Δ ࢓૊Έɻςετσʔλ͕ඞཁͳͷ͸ਏ͍ɻɻ

  27. ϕετϓϥΫςΟε UIฤ

  28. ϕετϓϥΫςΟε ϑΥʔϜ

  29. ϑΥʔϜฤ • 2017೥ͷformʹ͍ͭͯ • https://speakerdeck.com/yosuke_furukawa/ 2017nian-falseformfalsehua

  30. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY +BWB4DSJQUͷϝϞϦ

  31. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY +BWB4DSJQUͷϝϞϦ 6ODPOUSPMMFE 'PSN $POUSPMMFE

    'PSN
  32. Uncontrolled vs Controlled • DOMͷ஋Λ௚઀࢖͏ (Uncontrolled) • DOM͔Βऔ͖ͬͯͨ஋ΛJSͷϝϞϦʹೖΕ ͯɺεφοϓγϣοτͱͯ͠࢖͏ (Controlled)

  33. Uncontrolled form // React ͩͱ͜͏ class NameForm extends React.Component {

    // … handleSubmit(event) { alert('A name was submitted: ' + this.input.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" ref={(input) => this.input = input} /> </label> <input type="submit" value="Submit" /> </form> ); } }
  34. Controlled form class NameForm extends React.Component { // … handleChange(event)

    { this.setState({value: event.target.value}); } handleSubmit(event) { alert('A name was submitted: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" value={this.state.value} onChange={this.handleCha </label> <input type="submit" value="Submit" /> </form> ); } }
  35. Uncontrolled vs Controlled • Controlled ͳํ͸ ͜͜Ͱ͸ React ͷ state

    ͱ ͯ͠؅ཧ͢Δ • Uncontrolled ͳํ͸DOMʹ͚ͩ؅ཧͤ͞Δ
  36. Uncontrolled vs Controlled • Facebook ͕ਪ঑ͯ͠Δͷ͸ Controlled Ұ୒ • React

    ͷ v-dom ߋ৽ͷλΠϛϯάͱ΋߹Θͤͯ React ͕࠷దԽͨ͠ํ๏ͰDOMʹ൓өͤ͞Δ͜ͱ ͕Ͱ͖Δ • ͪΐͬͱڽͬͨformΛ࡞Ε͹େମControlledͰ࣮ ૷͢Δඞཁ͕ग़ͯ͘Δɻ
  37. Uncontrolled vs Controlled • jQuery UI Έ͍ͨͳϥΠϒϥϦ͸େମ Uncontrolled ͳํ๏Ͱ΍ͬͯΔ͜ͱ͕ଟ͍ʢؾ ͕͢Δʣ

    • طଘͷࢿ࢈͕jQueryʹ͋ͬͯͦΕ͕ Uncontrolled ͳํ๏Ͱ࣮ݱ͞ΕͯΔͳΒ࢖͏ͷ ΋ྑ͍͕ɺجຊ͸ Controlled Ͱྑ͍ؾ͕͢Δɻɹ
  38. Uncontrolled vs Controlled • https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/

  39. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY +BWB4DSJQUͷϝϞϦ 6ODPOUSPMMFE 'PSN ΋͏๨Εͯ΋ྑ͍͔΋

    $POUSPMMFE 'PSN ͓ͬͪ͜͢͢Ί
  40. Ͱ΋ 2017 ೥ݱࡏ͸ state ͕ ෳ਺͋Δ

  41. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%#

  42. Ͳ͜ʹ஋Λอଘ͢Δͷ͕ਖ਼͠ ͍ͷ͔ʁ

  43. None
  44. 6TF3FBDUGPSFQIFNFSBMTUBUFUIBUEPFTO`UNBUUFSUPUIF BQQHMPCBMMZ

  45. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# &QIFNFSBM

    &UFSOBM 'PSFWFS
  46. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# Ұ࣌తͳGPSNͷ஋

    ͳΒ͜͜ʹ HMPCBMͳTUBUFͳΒ ͜͜ʹ
  47. Ͱ΋΍ͬͯΈΔͱ

  48. React ͷ state ͱ Redux ͷ state Ͱ form ͔ͩΒͱ͍ͬͯ

    ෼͚Δͷ໘౗
  49. ࠓ͸

  50. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# ͳΜ͔ύϑΥʔϚϯεͷϘ

    τϧωοΫ͕͋ͬͨΒ͜͜ جຊ͜͜
  51. twitter Lite ͷߏ੒

  52. ࠓͷ form ͷ஋Λ؅ཧ͢Δ৔ॴ %0. 3FBDU 3FEVY -PDBMTUPSBHF DPPLJF *OEFYFE%# UXJUUFSͷGPSNͷ৘ใ͸

    Ұ୴͜͜ͰCV⒎FS ਺จࣈهड़ͨ͠Β SFEVDFSʹߦ͘
  53. ͋Δఔ౓ form ͷ৘ใ͸ React ͰͨΊͯɺ਺จࣈೖΕ ͨΒ Redux ʹ flush ͤ͞Δɻ

  54. ϕετϓϥΫςΟε Ծ૝εΫϩʔϧ

  55. Ծ૝εΫϩʔϧ • େલఏ: • DOMͷཁૉ͕૿͑Ε͹૿͑Δ΄Ͳϖʔδ͸ ॏ͘ͳΔ͠ɺΧΫͭ͘ • ϒϥ΢β্ͷϝϞϦ͕େ͖͘ͳΔ • ݟ͑ͯͳ͍ॴ͸DOMʹදࣔ͠ͳ͍͍ͯ͘

  56. Ծ૝εΫϩʔϧ • ݟ͑ͯΔͱ͜Ζ͚ͩDOMͱͯ͠දࣔ͢Δ • react-virtualized Λ࢖͏ %0.ͱͯ͠ දࣔ %0.͔Β ͸ഁغ

  57. ϕετϓϥΫςΟε ແݶεΫϩʔϧ

  58. ແݶεΫϩʔϧ • େલఏ: • Ϣʔβʔͷճ༡࣌ؒΛ૿΍͍ͨ͠ɻ
 ݕࡧͨ͠Β2ϖʔδ໨Ҏ߱΋ͪΌΜͱݟ͍ͤͨɻ • ͪ·ͪ·࣍΁ͱ͔ϖʔδͷϦϯΫΛԡ͞ͳ͖Ό͍͚ͳ͍ͷ͸໘ ౗ʢಛʹϞόΠϧʣ •

    ͔ͱݴͬͯSEO͸ઈରʢεΫϩʔϧ͢Δͷ͸Ϣʔβʔ͚ͩͰ Google Crawler͸εΫϩʔϧΠϕϯτ·ͰൃՐͯ͘͠Εͳ͍ʣ
  59. ແݶεΫϩʔϧ • ແݶεΫϩʔϧ x ϖʔδωʔγϣϯ • Ϣʔβʔ΋Ϋϩʔϥʔ΋
 ྆ํϑϨϯυϦʔʹɻ ໭Δ 1

    2 3 4 5 6 7 8 9 10 ࣍΁
  60. όουϊ΢ϋ΢ ΍ͬͯΈ͚ͨͲμϝͩͬͨฤ

  61. ϋϚΓ·ͬͨ͘ babel plugins

  62. babel-plugin-transform-react- inline-elementsͰIEͷࢮ

  63. transform-react-constant- elementsͰbabelόάΛ౿Ή

  64. transform-react-constant- elementsͰbabelόάΛ౿Ή • ൵C

  65. Α͘Α͘ߟ͑Δͱͨ͘͞Μ͋Δ • fetchrͷෆ۩߹Λ౿Μͩ
 ʢओʹηΩϡϦςΟ໘ʣ • React v15ͰϝϞϦʔϦʔΫʹ೰·͞ΕΔɺv16Ͱղফ • react-router v4ະରԠ

    • etc…
  66. Α͘Α͘ߟ͑Δͱͨ͘͞Μ͋Δ • fetchrͷෆ۩߹Λ౿Μͩ
 ʢओʹηΩϡϦςΟ໘ʣ • React v15ͰϝϞϦʔϦʔΫʹ೰·͞ΕΔɺv16Ͱղফ • react-router v4ະରԠ

    • etc… ܾͯ͠ॱ෩Ͱ͸ͳ͍͕ɺԶΒ͸΍ͬ ͍ͯͧ͘ʂʂʂʂ
  67. ·ͱΊ • ϕετϓϥΫςΟεʢΞʔΩςΫνϟฤʣ • ඇಉظϩʔυ • reduxϑϩʔ੍ޚ • ducks •

    APIఆٛ • ϕετϓϥΫςΟε(UIฤ) • ϑΥʔϜ • Ծ૝εΫϩʔϧ • ແݶεΫϩʔϧ • όουϓϥΫςΟε • babel plugin…, onlyUpdateForPropTypes…, etc