Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing construction parameters to redux middleware

I was curious if there is a way to pass a parameter to a middleware without retrieving it from the state. What I want to do is to pass a generic function that we are using that determines if the user is authenticated or not. So rather than retreiving the authentication information from the state which will be code duplication, I want to pass isAuthenticated function to the middleware.

I don't think this is implemented natively in applyMiddleware framework but maybe someone has a work around for this situation.

like image 991
ralzaul Avatar asked Aug 15 '16 09:08

ralzaul


2 Answers

Ok the right way to do this turned out to be a wrapper function that will wrap the actual middleware function

export const middlewareFunction = (store) => (next) => (action) => {
    do some stuff with something...
}

If this is your actual middleware function, than you should be applying the middleware as

applyMiddleware(middlewareFunction);

What you should be doing to pass a parameter is to implement a function like

export const middlewareWrapper = (args) => {
    do some stuff with your args 
    return (state) => (next) => (action) => {
        do more stuff with your args and actions
    }
} 

With this syntax you can apply the middleware as :

applyMiddleware(middlewareWrapper(args));
like image 128
ralzaul Avatar answered Sep 28 '22 16:09

ralzaul


Since actions passed to middleware don't have to be pure, you can pass a function as part of the action. Since the middleware has an access to the store, and using store.getState() to the state, we can apply the method to the state, and get a computed result.

In the api middleware from the real world example of redux you can see that the endpoint can be a function, and the actual endpoint can be computed from state (see the code between the asterisks comments):

export default store => next => action => {
  const callAPI = action[CALL_API]
  if (typeof callAPI === 'undefined') {
    return next(action)
  }

  let { endpoint } = callAPI
  const { schema, types } = callAPI

 /***************************************************************************/    
  /** if the endpoint is a function compute the actual endpoint from state ***/
  if (typeof endpoint === 'function') {
    endpoint = endpoint(store.getState())
  }
  /***************************************************************************/

  if (typeof endpoint !== 'string') {
    throw new Error('Specify a string endpoint URL.')
  }
  if (!schema) {
    throw new Error('Specify one of the exported Schemas.')
  }
  if (!Array.isArray(types) || types.length !== 3) {
    throw new Error('Expected an array of three action types.')
  }
  if (!types.every(type => typeof type === 'string')) {
    throw new Error('Expected action types to be strings.')
  }

  function actionWith(data) {
    const finalAction = Object.assign({}, action, data)
    delete finalAction[CALL_API]
    return finalAction
  }

  const [ requestType, successType, failureType ] = types
  next(actionWith({ type: requestType }))

  return callApi(endpoint, schema).then(
    response => next(actionWith({
      response,
      type: successType
    })),
    error => next(actionWith({
      type: failureType,
      error: error.message || 'Something bad happened'
    }))
  )
}
like image 30
Ori Drori Avatar answered Sep 28 '22 17:09

Ori Drori