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

Consuming services reliably in Redux without losing your mind

Consuming services reliably in Redux without losing your mind

We identify potential issues with the most common ways of consuming services. And, wait for it... Solve them.

Sidhartha Chatterjee

September 14, 2017
Tweet

More Decks by Sidhartha Chatterjee

Other Decks in Programming

Transcript

  1. Introduction • Redux is awesome • Patterns are awesome •

    Leave trial and error to the early adopters • Redux Middleware is very powerful • Simplicity winsTM
  2. Promises, Thunks, Sagas? • Manual fetch, success and failure actions

    are common • Sagas are complicated • Middleware is best • Redux Standard API-calling Actions (RSAAs) • Keep It Simple Silly
  3. Manually dispatching actions export const fetchPizza = (type) => {

    return (dispatch, getState) => { dispatch({ type: FETCH_PIZZA }) return fetch(`https://hipsters.pizza/${type}`) .then(response => response.json()) .then(pizza => dispatch({ type: RECEIVE_PIZZA, pizza })) .catch(error => dispatch({ type: FAILURE_PIZZA, error })) } }
  4. API Middleware export function createApiMiddleware() { return store => next

    => action => { const apiService = new ApiService( apiAction, store.dispatch ); return apiService.call(); } }
  5. Automating the dispatches export class ApiService { call() { this.startApiRequest()

    return fetch.apply(this, fetchArgs) .then(checkResponseIsOk) .then(completeApiRequest) .catch(catchApiRequestError); } }
  6. Manual Authorisation export const fetchPizza = (type) => { return

    (dispatch, getState) => { dispatch({ type: FETCH_PIZZA }) return fetch(`https://hipsters.pizza/${type}`, { headers: { 'Authorization': 'Bearer ' + getState().token } }) } }
  7. Refresh tokens automatically export class ApiService { call() { if

    (this.shouldRefreshToken() { this.fetchNewToken() .then((newToken) => { this.startApiRequest() ... }) } else { this.startApiRequest() ... } } }
  8. Refresh tokens automatically export class ApiService { catchApiRequestError() { const

    maxAttempts = 5 const retryFactor = 10 ... return this.call(...) } // Retry till you can and then dispatch failure call() { this.startApiRequest() return fetch.apply(this, fetchArgs) .then(checkResponseIsOk) .then(this.completeApiRequest) .catch(this.catchApiRequestError); } }
  9. Cache? • Offline • localStorage, AsyncStorage, the kitchen sink •

    Browsers with no service workers (Hey there, Safari) • React Native, Desktop apps • yarn add redux-persist ( Zack)
  10. Persist your store const store = createStore( combineReducers(reducers), initialState, compose(

    applyMiddleware(...middleware), autoHydrate() ) ) persistStore(store) persistStore(store, { whitelist: ['cart', 'checkout'] })
  11. Buffer actions before rehydration import createActionBuffer from 'redux-action-buffer' const store

    = createStore( combineReducers(reducers), initialState, compose( applyMiddleware(...middleware, createActionBuffer(REHYDRATE)), autoHydrate() ) )