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

Redux Middleware Wars (English)

Redux Middleware Wars (English)

My talk at M3 Tech meetup! #2 -Front-end side effects-
http://m3-engineer.connpass.com/event/33802/

Shuhei Kagawa

July 14, 2016
Tweet

More Decks by Shuhei Kagawa

Other Decks in Technology

Transcript

  1. Redux
    Middleware Wars

    View Slide

  2. Me
    • So$ware Engineer at M3, Inc.
    • Developing medical apps
    • AngularJS, Rails, Node.js, Babel, etc.
    • GitHub, Qiita: @shuhei
    • TwiKer: @shuheikagawa
    • ! 2nd-grade Beer CerPficate

    View Slide

  3. Before star*ng to talk about Redux middlewares...

    View Slide

  4. What's Redux at all?
    • Predictable state container for JavaScript apps
    • Something like Flux that was originally created for >me traveling
    and hot reloading

    View Slide

  5. 3 principles of Redux
    1. Express all the app state as a single
    Object (State)
    2. You can update State only by
    dispatching Action, or rather a new
    State is created
    3. State is updated by pure func)ons
    called Reducer, which always returns
    the same result for each set of
    arguments
    reducer : (State, Action) -> State

    View Slide

  6. ! Pure func)on
    • Idempotent: Return value is calculated only by arguments
    • No side-effect: Does not change states outside of the func>on

    View Slide

  7. ! Impure func+on
    • Returns different values from 3me to 3me
    • Returns nothing
    • Mutates passed arguments
    • Calls a callback func3on later
    • etc.

    View Slide

  8. You won't overlook
    state change

    View Slide

  9. View Slide

  10. So, what about side effects?
    • AJAX
    • local storage
    • cookie
    • logging
    • etc.

    View Slide

  11. • Do in Reducer: Please don't
    • Do in view component: We want to keep components as simple
    as possible
    • Do in AceffecBul ac

    View Slide

  12. Middleware

    View Slide

  13. What's Redux Middleware
    • Do something befor/a2er dispatch
    call
    • You can receive an Action and do
    something with it:
    • Delay Action
    • Replace an Action to another one
    • Do asynchronous thing and dispatch
    the result as an Action
    • e.g. WSGI, Rack, Express, Koa, etc.

    View Slide

  14. Example 1: Do nothing
    Pass through the received ac0on to the next middleware
    const passthrough = store => next => action => {
    return next(action);
    };

    View Slide

  15. Example 2: Logging
    Log before and a,er dispatching an ac3on (next()) to the next
    middleware
    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;
    };

    View Slide

  16. Example 3: Wait for the result of a 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);

    View Slide

  17. This talk focuses on middlewares
    that handle general-purpose
    asynchronous procedures

    View Slide

  18. What I want
    • ! Testability without mocking
    • " Control 7ming (thro9ling, debouncing)
    • # Cohesion of complex logic (wizard, etc.)
    • ✨ Ac7veness of development

    View Slide

  19. Middlewares for asynchronous handling
    From my biased perspec/ve...
    | ----------------- | ---- | --------- | ---- | ---- | ---- | ---- |
    | 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 |
    | ----------------- | ---- | --------- | ---- | ---- | ---- | ---- |
    The numbers of ⭐ were recorded on June 5th, 2016

    View Slide

  20. redux-thunk ⭐2392
    Executes the func,on with dispatch and getState as
    arguments if an Action is a func,on (thunk)
    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());

    View Slide

  21. redux-thunk ⭐2392
    • ! Requires mocking for tes2ng
    • " Hard to do debouncing because it takes ac2ons one by one
    • # Able to describe complex logic
    • ✨ Well maintained (actually only 13 lines of code!)
    • Reference: How to dispatch a Redux ac2on with a 2meout?

    View Slide

  22. redux-promise ⭐864
    Resolves a Promise payload of a FSA, Flux Standard Ac7on and
    dispatches the result
    function fetchItems() {
    const promise = fetch('/items').then(res => res.json());
    return {
    type: 'FETCH_ITEMS',
    payload: promise
    };
    }
    dispatch(fetchItems());

    View Slide

  23. redux-promise ⭐864
    • ! Too simple to test
    • " Can't do debouncing and etc.
    • # Too simple for complex logic
    • ✨ No commit in the last 4 months (only 25 lines of code
    though...)
    • A seemingly important MR for error handling has been merged
    but not released

    View Slide

  24. redux-saga ⭐3172
    Describes opera,ons with side effects in generator called 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);
    }

    View Slide

  25. redux-saga ⭐3172
    • ! Super easy to test!!!
    • yields side effect requests, has the middleware to execute
    them, and receives the response
    • Able to describe complex asynchronous opera=ons while
    keeping them pure
    • See the upcoming talk by @kuy

    View Slide

  26. redux-loop (store enhancer) ⭐641
    API designed a,er Elm. reducer returns Effects in addi4on to
    state
    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;
    }
    }

    View Slide

  27. redux-loop (store enhancer) ⭐641
    • ! Mock-free tes-ng
    • Effects are plain Objects. Side effects won't happen un-l
    executed
    • " hard to do debouncing and etc.
    • # Composable Effects
    • ✨ Not maintained for 3 months. The author has completely
    moved to the Elm world?

    View Slide

  28. redux-observable ⭐ 634
    Receives an Observable and returns an
    Observable of addi0onal Actions
    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$
    );
    }

    View Slide

  29. redux-observable ⭐ 634
    • ! Needs mocking to test epics
    • " Able to control 4me by Rx's powerful operators
    • # Progressed into background processor style like redux-saga
    • Able to express complex procedure
    • ✨ Being ac4vely developed and super simple source code
    • Rx is fun to use!

    View Slide

  30. Trend (?)
    • Side effects as data (redux-saga, redux-loop, Cycle.js)
    • Middleware handles side effect requests
    • App logic is kept clean
    • Background processor style (redux-saga, redux-observable, choo)
    • receives Actions a"er reducer instead of before reducer

    View Slide

  31. Thanks!

    View Slide

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

    View Slide