Skip to content

Instantly share code, notes, and snippets.

@Jonalogy
Last active December 7, 2022 15:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jonalogy/53d43e107edbde1178b36671fbe53010 to your computer and use it in GitHub Desktop.
Save Jonalogy/53d43e107edbde1178b36671fbe53010 to your computer and use it in GitHub Desktop.
How Do Middlewares work

How Do Middlewares work?

Here're my learnings from Redux Docs on Middlewares. If you haven't read through the docs yet, please do so first.

Middlewares

Middlewares work with the beauty of Currying.

What is Currying?

The concept of using a Higher Order Function to generate a new function with the partial application or all of its arguments.

const CurryMaker = ingredients => {
  const SecretIngredient = "Fairy's Dust";
  const Grinded = ingredients.reduce(  (string , igd)=>`${string} + ${igd}` , '')

  return water => water + ' + ' + Grinded + ' + ' +  SecretIngredient
  //Notice that running CurryMaker() returns a new function!
}

const Curry = CurryMaker(['Tumeric' , 'Cumin' , 'Chilli'])('Water')
console.log(Curry) //-> Water +  + Tumeric + Cumin + Chilli + Fairy's Dust

Below are two middleware examples from the docs, notice that each middleware is conceptually made up of 3 tiers of currying.

const logger = store => next => action => next(action)

const crashReporter = store => next => action => {
  try next(action)
  catch (err) {
    console.error('Caught an exception!', err)
    Raven.captureException(err, {
      extra: { action, state: store.getState() }
    })
    throw err
  }
}

Through applyMiddleware, all middlewares will be curried together to form one huge function that all actions in your application will run through. Though not the real code under the hood, understanding of official doc's Attempt #6: Naïvely Applying the Middleware provides great insight to applyMiddleware.

// store = The entire Redux store
// middleware = Assume an array of middlewares

function applyMiddleware(store, middlewares) {
   middlewares = middlewares.slice()
   middlewares.reverse()
   let dispatch = store.dispatch
   middlewares.forEach(middleware =>
     dispatch = middleware(store)(dispatch)
   )
   return Object.assign({}, store, { dispatch })
 }

applyMiddleware(store , [logger, crashReporter])

Lets go deeper to appreciate the beauty.

After middlewares.reverse(), the forEach() iterator first handles crashReporter with store.dispatch as the 2nd curry argument.

The first iteration results to:

const firstIteration = crashReporter(store)(store.dispatch)

firstIteration = action => { try store.dispatch(action)
                             catch (err) {
                              console.error('Caught an exception!', err)
                              Raven.captureException(err, {
                                extra: { action, state: store.getState() }
                              })
                              throw err
                             }
                            }

On the second iteration...

const secondIteration = logger(store)(firstIteration)

secondIteration = action => firstIteration(action)

secondIteration = action => action => { try store.dispatch(action)
                                        catch (err) {
                                          console.error('Caught an exception!', err)
                                          Raven.captureException(err, {
                                            extra: { action, state: store.getState() }
                                          })
                                          throw err
                                        }
                                      }

If there are any more applied middlewares, now you can see how currying builds up one gigantic middleware function and any action object will be passed as its parameter! This currying would also mean you can control the execution of middlewares in the sequence of how you arrange your middleware!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment