Slide 1

Slide 1 text

Redux Middleware Wars

Slide 2

Slide 2 text

Me • So$ware Engineer at M3, Inc. • ҩྍݱ৔Ͱ࢖͏γεςϜͷ։ൃ • AngularJS, Rails, Node.js, Babel, etc. • GitHub, Qiita: @shuhei • TwiGer: @shuheikagawa • ! Ϗʔϧݕఆ 2 ڃ

Slide 3

Slide 3 text

Middleware ʹ͍ͭͯ࿩ͦ͢ͷલʹɾɾɾ

Slide 4

Slide 4 text

ͦ΋ͦ΋ Redux ͱ͸ʁ • Predictable state container for JavaScript apps • ༧ଌՄೳͳঢ়ଶίϯςφʢ௚༁ʣ • ΋ͱ΋ͱ͸ Time traveling, hot reloading Λ໨తͱͯ͠࡞ΒΕͨ Flux తͳԿ͔

Slide 5

Slide 5 text

Redux ͷ 3 ݪଇ 1. ΞϓϦͷશঢ়ଶΛҰͭͷ Object (State) ͱͯ͠อ࣋ 2. Action ΛૹΔʢdispatchʣ͜ͱʹ ΑͬͯͷΈ State ΛมߋͰ͖Δʢͱ͍ ͏͔৽͍͠ State ͕࡞ΒΕΔʣ 3. Reducer ͱ͍͏ pure ͳؔ਺ʢಉ͡Ҿ ਺ʹରͯ͠ৗʹಉ͡ฦΓ஋Λฦ͢ʣʹ ΑͬͯͷΈঢ়ଶ͕มߋ͞ΕΔ reducer : (State, Action) -> State

Slide 6

Slide 6 text

! Pure ͳؔ਺ͱ͸ʁ • Ҿ਺ͷΈʹΑͬͯฦΓ஋͕ܾ·Δ • ؔ਺ͷ֎ͷঢ়ଶΛมߋ͠ͳ͍ʢ෭࡞༻͕ͳ͍ʣ

Slide 7

Slide 7 text

! Pure ͡Όͳ͍ؔ਺ • ࣌ʹΑͬͯฦ͢஋͕ҧ͏ • ฦΓ஋͕ͳ͍ • Ҿ਺Λมߋͯ͠͠·͏ • ޙͰίʔϧόοΫ͕ݺ͹ΕΔ • etc.

Slide 8

Slide 8 text

஌Β͵ؒʹΞϓϦ ͷঢ়ଶ͕มΘΔ͜ ͱ͕ͳ͍

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

• Reducer ͷதʹॻ͘: ແཧ • View Component ͷதʹॻ͘: ͔ͤͬ͘ঢ়ଶΛ௥͍ग़ͨ͠ͷ ʹɾɾɾ • Ac4on Creator ͷதʹॻ͘: dispatch Λ౉͢ඞཁ͋Γ

Slide 12

Slide 12 text

Middleware

Slide 13

Slide 13 text

Redux Middleware ͱ͸ • dispatch ͷલޙʹॲཧΛڬΉ • Action Λड͚ͯɺΰχϣΰχϣͰ͖ Δ • Action Λͪΐͬͱ஗ΒͤͯૹΔ • ผͷ Action ʹஔ͖׵͑Δ • ඇಉظॲཧΛߦ͍ɺ݁ՌΛ Action ͱͯ͠ૹΔ • e.g. WSGI, Rack, Express, Koa, etc.

Slide 14

Slide 14 text

ྫ: ͳʹ΋͠ͳ͍ ड͚औͬͨ Ac$on Λͦͷ··࣍ͷ middleware ʹ౤͛Δ const passthrough = store => next => action => { return next(action); };

Slide 15

Slide 15 text

ྫ: ϩάΛग़ྗ ࣍ͷ 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; };

Slide 16

Slide 16 text

ྫ: 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);

Slide 17

Slide 17 text

ࠓճ͸ඇಉظॲཧΛߦ͏ Middleware ʹয఺

Slide 18

Slide 18 text

΄͍͠΋ͷ • ! ςετͷ͠΍͢͞ʢϞοΫແ͠ͰςετͰ͖Δͱ࠷ߴʣ • " ۭ࣌Λ௒͑Δʢthro'ling, debouncingʣ • # ϩδοΫͷڽू౓ • ✨ ։ൃͷ׆ൃ͞

Slide 19

Slide 19 text

ඇಉظॲཧΛߦ͏ 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 ௐ΂

Slide 20

Slide 20 text

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());

Slide 21

Slide 21 text

redux-thunk ⭐2392 • ! ϞοΫ͠ͳ͍ͱςετ͕ॻ͚ͳ͍ • " Ac%on ΛҰ͔ͭͮͭ͠ड͚ΒΕͳ͍ͷͰɺdebounce ͳͲ͕ ೉͍͠ • # ΄Ͳ΄ͲʹෳࡶͳϩδοΫ͸ॻ͚Δ • ✨ ΄Ͳ΄Ͳʹϝϯς͞Ε͍ͯΔɻͦ΋ͦ΋ 13 ߦ͔͠ͳ͍ • ࢀߟ: How to dispatch a Redux ac%on with a %meout?

Slide 22

Slide 22 text

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());

Slide 23

Slide 23 text

redux-promise ⭐864 • ! γϯϓϧͳͷͰɺͦ͜·Ͱςετ͠ͳͯ͘ྑͦ͞͏ • " debounce ͳͲ΋Ͱ͖ͳ͍ • # ෳࡶͳϩδοΫ͸ॻ͚ͳ͍ • ✨ 4 ϲ݄ఔϝϯς͞Εͯͳ͍ɻ25 ߦ͚͕ͩͩɾɾɾ • Τϥʔॲཧͷൺֱతॏཁͦ͏ͳ MR ͕Ϛʔδ͞Ε͕ͨϦϦʔ ε͞Ε͍ͯͳ͍

Slide 24

Slide 24 text

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); }

Slide 25

Slide 25 text

redux-saga ⭐3172 • ! ςετ͕͠΍͍͢ʂʂʂ • ෭࡞༻ϦΫΤετΛ yield ͯ͠ɺmiddleware ʹ࣮ߦͯ͠΋ Β͍ɺ݁ՌΛड͚औΔ • ࣗ෼͸ pure ͳ··ෳࡶͳඇಉظॲཧ͕ॻ͚Δ • ৄ͘͠͸ @kuy ͞Μͷ͓࿩Ͱɾɾɾ

Slide 26

Slide 26 text

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; } }

Slide 27

Slide 27 text

redux-loop (store enhancer) ⭐641 • ! ϞοΫͳ͠ͰςετͰ͖Δ • Effects ͸ͨͩͷ Objectɻ࣮ߦ͢Δ·Ͱ෭࡞༻͸ى͖ͳ͍ • " debounce ͳͲ͸Ͱ͖ͳͦ͞͏ • # Effects Λ૊Έ߹ΘͤΔ͜ͱ͕Ͱ͖Δ • ✨ 3 ϲ݄΄Ͳϝϯς͞Ε͍ͯͳ͍ɻ࡞ऀ͕ Elm ͔͠ॻ͔ͳ͘ ͳͬͯ͠·ͬͨʁ

Slide 28

Slide 28 text

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$ ); }

Slide 29

Slide 29 text

redux-observable ⭐ 634 • ! ϞοΫ͠ͳ͍ͱςετͰ͖ͳ͍ • " Rx ͷڧྗͳ operator Ͱ༰қʹۭ࣌Λ੍ͤΔ • # redux-saga తͳ background processor style ʹਐԽ • ෳࡶͳॲཧ΋ॻ͚Δ • ✨ ݱࡏ΋։ൃதɻͱͯ΋γϯϓϧ • Rx ͸ΩϚΔͱؾ͍͍࣋ͪʢݸਓͷײ૝ʣ

Slide 30

Slide 30 text

τϨϯυʢʁʣ • σʔλͱͯ͠ͷ෭࡞༻ʢsaga, loop, Cycle.jsʣ • ෭࡞༻ϦΫΤετΛ middleware ͕ॲཧ͢Δ • ։ൃऀ͕ॻ͘ϩδοΫ͕៉ྷʹอͯΔ • Background processor ελΠϧʢsaga, observable, chooʣ • reducer ͷલͰ͸ͳ͘ޙͰ Action Λड͚Δ

Slide 31

Slide 31 text

࠙਌ձͰ͍Ζ͍Ζڭ͑ͯԼ͍͞ʂ

Slide 32

Slide 32 text

Thanks!

Slide 33

Slide 33 text

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