Redux Middleware Wars (Japanese)

Redux Middleware Wars (Japanese)

M3 Tech meetup! #2 ~フロントエンドの副作用~
http://m3-engineer.connpass.com/event/33802/

Ca0ab6e450f894e06652ee257df9d647?s=128

Shuhei Kagawa

July 14, 2016
Tweet

Transcript

  1. Redux Middleware Wars

  2. Me • So$ware Engineer at M3, Inc. • ҩྍݱ৔Ͱ࢖͏γεςϜͷ։ൃ •

    AngularJS, Rails, Node.js, Babel, etc. • GitHub, Qiita: @shuhei • TwiGer: @shuheikagawa • ! Ϗʔϧݕఆ 2 ڃ
  3. Middleware ʹ͍ͭͯ࿩ͦ͢ͷલʹɾɾɾ

  4. ͦ΋ͦ΋ Redux ͱ͸ʁ • Predictable state container for JavaScript apps

    • ༧ଌՄೳͳঢ়ଶίϯςφʢ௚༁ʣ • ΋ͱ΋ͱ͸ Time traveling, hot reloading Λ໨తͱͯ͠࡞ΒΕͨ Flux తͳԿ͔
  5. Redux ͷ 3 ݪଇ 1. ΞϓϦͷશঢ়ଶΛҰͭͷ Object (State) ͱͯ͠อ࣋ 2.

    Action ΛૹΔʢdispatchʣ͜ͱʹ ΑͬͯͷΈ State ΛมߋͰ͖Δʢͱ͍ ͏͔৽͍͠ State ͕࡞ΒΕΔʣ 3. Reducer ͱ͍͏ pure ͳؔ਺ʢಉ͡Ҿ ਺ʹରͯ͠ৗʹಉ͡ฦΓ஋Λฦ͢ʣʹ ΑͬͯͷΈঢ়ଶ͕มߋ͞ΕΔ reducer : (State, Action) -> State
  6. ! Pure ͳؔ਺ͱ͸ʁ • Ҿ਺ͷΈʹΑͬͯฦΓ஋͕ܾ·Δ • ؔ਺ͷ֎ͷঢ়ଶΛมߋ͠ͳ͍ʢ෭࡞༻͕ͳ͍ʣ

  7. ! Pure ͡Όͳ͍ؔ਺ • ࣌ʹΑͬͯฦ͢஋͕ҧ͏ • ฦΓ஋͕ͳ͍ • Ҿ਺Λมߋͯ͠͠·͏ •

    ޙͰίʔϧόοΫ͕ݺ͹ΕΔ • etc.
  8. ஌Β͵ؒʹΞϓϦ ͷঢ়ଶ͕มΘΔ͜ ͱ͕ͳ͍

  9. None
  10. ͱ͸͍͑ɺ෭࡞༻͸Ͳ͏͢Δͷʁ • AJAX • local storage • cookie • ϩά

    • etc.
  11. • Reducer ͷதʹॻ͘: ແཧ • View Component ͷதʹॻ͘: ͔ͤͬ͘ঢ়ଶΛ௥͍ग़ͨ͠ͷ ʹɾɾɾ

    • Ac4on Creator ͷதʹॻ͘: dispatch Λ౉͢ඞཁ͋Γ
  12. Middleware

  13. Redux Middleware ͱ͸ • dispatch ͷલޙʹॲཧΛڬΉ • Action Λड͚ͯɺΰχϣΰχϣͰ͖ Δ

    • Action Λͪΐͬͱ஗ΒͤͯૹΔ • ผͷ Action ʹஔ͖׵͑Δ • ඇಉظॲཧΛߦ͍ɺ݁ՌΛ Action ͱͯ͠ૹΔ • e.g. WSGI, Rack, Express, Koa, etc.
  14. ྫ: ͳʹ΋͠ͳ͍ ड͚औͬͨ Ac$on Λͦͷ··࣍ͷ middleware ʹ౤͛Δ const passthrough =

    store => next => action => { return next(action); };
  15. ྫ: ϩάΛग़ྗ ࣍ͷ middleware ʹ ac+on Λ౤͛ΔʢnextʣલޙͰϩάΛग़ྗ const logger =

    store => next => action => { console.log('prev state', store.getState()); console.log('action', action); const returnValue = next(action); console.log('next state', store.getState()); return returnValue; };
  16. ྫ: Promise ͷ݁ՌΛ଴ͭ const promise = store => next =>

    action => { if (typeof action.then === 'function') { return action.then(store.dispatch); } else { return next(action); } }; function fetchPosts() { return fetch('/posts').then(res => res.json()) .then(posts => ({ type: 'POSTS_FETCHED', posts })); } dispatch(fetchPosts);
  17. ࠓճ͸ඇಉظॲཧΛߦ͏ Middleware ʹয఺

  18. ΄͍͠΋ͷ • ! ςετͷ͠΍͢͞ʢϞοΫແ͠ͰςετͰ͖Δͱ࠷ߴʣ • " ۭ࣌Λ௒͑Δʢthro'ling, debouncingʣ • #

    ϩδοΫͷڽू౓ • ✨ ։ൃͷ׆ൃ͞
  19. ඇಉظॲཧΛߦ͏ Middleware ಠஅͱภݟʹΑΓ... | ----------------- | ---- | --------- |

    ---- | ---- | ---- | ---- | | name | star | from | test | time | cohe | acti | | ----------------- | ---- | --------- | ---- | ---- | ---- | ---- | | redux-thunk | 2392 | '15/07/13 | C | C | B | A | | redux-promise | 864 | '15/07/02 | - | C | C | C | | redux-saga | 3172 | '15/11/30 | B | A | A | A | | redux-loop | 641 | '16/01/06 | A | C | B | C | | redux-observable | 634 | '16/02/16 | C | A | B | A | | ----------------- | ---- | --------- | ---- | ---- | ---- | ---- | ⭐ ͷ਺͸ 2016/7/5 ௐ΂
  20. redux-thunk ⭐2392 Ac#on ͱͯؔ͠਺ʢthunkʣ͕དྷͨΒɺͦΕΛ࣮ߦ͢ΔʢҾ਺ʹ dispatch ͱ getStateʣ const fetchBeers =

    () => (dispatch, getState) => { return fetch('/beers') .then(res => res.json()) .then(items => dispatch('FETCH_BEERS_SUCCEEDED', items)) .catch(error => dispatch('FETCH_BEERS_FAILED', error)); }; dispatch(fetchBeers());
  21. redux-thunk ⭐2392 • ! ϞοΫ͠ͳ͍ͱςετ͕ॻ͚ͳ͍ • " Ac%on ΛҰ͔ͭͮͭ͠ड͚ΒΕͳ͍ͷͰɺdebounce ͳͲ͕

    ೉͍͠ • # ΄Ͳ΄ͲʹෳࡶͳϩδοΫ͸ॻ͚Δ • ✨ ΄Ͳ΄Ͳʹϝϯς͞Ε͍ͯΔɻͦ΋ͦ΋ 13 ߦ͔͠ͳ͍ • ࢀߟ: How to dispatch a Redux ac%on with a %meout?
  22. redux-promise ⭐864 FSA (Flux Standard Ac/on) ͷ payload ͷ promise

    Λղܾ͠ɺ Ac/on ͱͯ͠ૹΓ௚ͯ͘͠ΕΔ function fetchItems() { const promise = fetch('/items').then(res => res.json()); return { type: 'FETCH_ITEMS', payload: promise }; } dispatch(fetchItems());
  23. redux-promise ⭐864 • ! γϯϓϧͳͷͰɺͦ͜·Ͱςετ͠ͳͯ͘ྑͦ͞͏ • " debounce ͳͲ΋Ͱ͖ͳ͍ •

    # ෳࡶͳϩδοΫ͸ॻ͚ͳ͍ • ✨ 4 ϲ݄ఔϝϯς͞Εͯͳ͍ɻ25 ߦ͚͕ͩͩɾɾɾ • Τϥʔॲཧͷൺֱతॏཁͦ͏ͳ MR ͕Ϛʔδ͞Ε͕ͨϦϦʔ ε͞Ε͍ͯͳ͍
  24. redux-saga ⭐3172 Saga ͱݺ͹ΕΔ generator (saga) Ͱ෭࡞༻Λ൐͏ॲཧΛهड़ function* fetchBeer(action) {

    try { const beers = yield call(fetchBeer, action.id); yield put({ type: 'FETCH_BEER_SUCCEEDED', payload: beers }); } catch (error) { yield put({ type: 'FETCH_BEER_FAILED', error }); } } function* watchFetchBeer() { yield* takeEvery('FETCH_BEER', fetchBeer); }
  25. redux-saga ⭐3172 • ! ςετ͕͠΍͍͢ʂʂʂ • ෭࡞༻ϦΫΤετΛ yield ͯ͠ɺmiddleware ʹ࣮ߦͯ͠΋

    Β͍ɺ݁ՌΛड͚औΔ • ࣗ෼͸ pure ͳ··ෳࡶͳඇಉظॲཧ͕ॻ͚Δ • ৄ͘͠͸ @kuy ͞Μͷ͓࿩Ͱɾɾɾ
  26. redux-loop (store enhancer) ⭐641 Elm Λਅࣅͨ APIɻreducer ͕ state ͚ͩͰͳ͘

    Effects ΋ฦ͢ function beers(state = [], action) { switch (action.type) { case 'FETCH_BEERS': return loop(state, Effects.promise(fetchBeers)); case 'FETCH_BEERS_SUCCEEDED': return action.payload; default: return state; } }
  27. redux-loop (store enhancer) ⭐641 • ! ϞοΫͳ͠ͰςετͰ͖Δ • Effects ͸ͨͩͷ

    Objectɻ࣮ߦ͢Δ·Ͱ෭࡞༻͸ى͖ͳ͍ • " debounce ͳͲ͸Ͱ͖ͳͦ͞͏ • # Effects Λ૊Έ߹ΘͤΔ͜ͱ͕Ͱ͖Δ • ✨ 3 ϲ݄΄Ͳϝϯς͞Ε͍ͯͳ͍ɻ࡞ऀ͕ Elm ͔͠ॻ͔ͳ͘ ͳͬͯ͠·ͬͨʁ
  28. redux-observable ⭐ 634 reducer ͷޙͰ Action Λड͚ͯ Action Λग़ྗ͢Δ Observable

    Λฦ͢ function beerEpic(action$, store) { const beers$ = action$.ofType('FETCH_ITEMS') .mergeMap(() => Observable.fromPromise(fetchBeers())) .map(beers => ({ type: 'FETCH_BEERS_SUCCEEDED', payload: beers })); return Observable.merge( beers$, something$ ); }
  29. redux-observable ⭐ 634 • ! ϞοΫ͠ͳ͍ͱςετͰ͖ͳ͍ • " Rx ͷڧྗͳ

    operator Ͱ༰қʹۭ࣌Λ੍ͤΔ • # redux-saga తͳ background processor style ʹਐԽ • ෳࡶͳॲཧ΋ॻ͚Δ • ✨ ݱࡏ΋։ൃதɻͱͯ΋γϯϓϧ • Rx ͸ΩϚΔͱؾ͍͍࣋ͪʢݸਓͷײ૝ʣ
  30. τϨϯυʢʁʣ • σʔλͱͯ͠ͷ෭࡞༻ʢsaga, loop, Cycle.jsʣ • ෭࡞༻ϦΫΤετΛ middleware ͕ॲཧ͢Δ •

    ։ൃऀ͕ॻ͘ϩδοΫ͕៉ྷʹอͯΔ • Background processor ελΠϧʢsaga, observable, chooʣ • reducer ͷલͰ͸ͳ͘ޙͰ Action Λड͚Δ
  31. ࠙਌ձͰ͍Ζ͍Ζڭ͑ͯԼ͍͞ʂ

  32. Thanks!

  33. Credits • Chart of Redux from h0p:/ /www.bebe0erdeveloper.com/coding/ ge=ng-started-react-redux.html