Redux middleware question

I got really hard time with Redux middleware, in the following code, could anybody explain the detailed purpose and function and use of const handleAsync function and the Redux.applyMiddleware(ReduxThunk.default) in the following code? this code is from Redux 12 Use Middleware to Handle Asynchronous Actions under http://hysterical-amusement.surge.sh/. Thanks!

const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'

const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }

const handleAsync = () => {
	return function(dispatch) {
		dispatch(requestingData());
		setTimeout(function() {
			let data = {
				users: ['Jeff', 'William', 'Alice']
			}
			dispatch(receivedData(data));
		}, 2500);
	}
};

const defaultState = {
	fetching: false,
	users: []
};

const asyncDataReducer = (state = defaultState, action) => {
	switch(action.type) {
		case REQUESTING_DATA:
			return {
				fetching: true,
				users: []
			}
		case RECEIVED_DATA:
			return {
				fetching: false,
				users: action.users
			}
		default:
			return state;
	}
};

const store = Redux.createStore(
	asyncDataReducer,
	Redux.applyMiddleware(ReduxThunk.default)
);

I cleaned up your code.
You need to use triple backticks to post code to the forum.
See this post for details.

Thanks for your help!

Redux middleware is pretty straightforward. Imagine the data flowing from a source and reaching a destination. As the name suggests, middleware sits in the middle of this, and it can be used to process data before it reaches the destination. Imagine your app just processes a bunch of numbers for the user. They get typed into a text input, which triggers actions that sends those numbers through Redux to be dealt with as state in your app. You could use middleware to double each number, wrap every 5 numbers in a function, or anything else your twisted mind can come up with. In order for middleware to be used, it needs to be added to the store. Middleware is really just a function that takes input, processes the input, and then calls the next function in the processing chain.

Redux.applyMiddleware is a function that takes some middleware and adds your store’s dispatch function to it. ReduxThunk is middleware that turns action creators into thunks, which makes dealing with asynchronicity easier. handleAsync, on the other hand, doesn’t have anything to do with middleware in the code provided because it’s not being used. Here are some useful resources for further learning:

Watch this whole playlist and follow along:

5 Likes

Action creators in redux typically return a normal object. However with middleware, Redux can handle asynchronous functions. handleAsync is an action creator which returns a function. The fact that the action creator returns a functions signals to your Redux middleware to handle the execution of the returned function.

As PortableStick mentioned, middleware sits in between a request and a response and has access to both the request and the response so middleware can perform actions on either. Maybe it could be compared to a kitchen where the chef cooks the food and the server delivers it. In between there is a guy who plates the food and puts on the garnish. He’s the middleware.

Within handleAsync there is a setTimeout function that delays the functions execution by 2.5s after which the receivedData action creator is dispatched with the data object. I think the setTimeout here is to mimic a REST API, which takes a bit to respond with requested data.

The pattern of dispatching actions from within the returned function is a common pattern you see in Redux. For instance the dispatch(requestingData()) likely updates a property within the store that can be used to signal the UI that a request is in progress. Think like a spinner on a website when you submit a form. The spinner could be a component which is rendered when requestingData triggers and is unmounted when receivedData resolves. Hope this helps!

5 Likes

thanks for all the detailed answers! I really appreciate! Happy New Year!

if handleAsync is a action creator, what is its specific use in the original code?
if I add following code to the original code? why are there following problems?

store.subscribe(()=>{
  console.log('code is executed: ', state.getState())
})// why doesnt log anything?? means store.dispatch(handleAsync()) did not fire??

store.dispatch(handleAsync());//should use action creator like this?

console.log(store.getState());//why shows nothing?

in the following original code, why dispatch can be an argument? totally don’t understand this original handleAsync code.

const handleAsync = () => {
	return function(dispatch) {
		dispatch(requestingData());
		setTimeout(function() {
			let data = {
				users: ['Jeff', 'William', 'Alice']
			}
			dispatch(receivedData(data));
		}, 2500);
	}
};

This is for redux-thunk. handleAsync is a function that returns another function. The second function has everything it needs to perform some asynchronous action except for the store’s dispatch function. handleAsync isn’t an action creator, it’s meant to be async middleware, I think. Might be wrong, though.

thanks for the response, still didn’t get it, but i just pass for right now. i just have too many questions everyday. another simple question:
in the following reducer, if state=[] is the argument, then if state were changed to e.g. [‘lee’], and store.dispatach again, will the state be changed back to [] at first? or the state will be changed from [‘lee’]?

const messageReducer = (state = [], action) => {
  switch (action.type) {
    case ADD:
      return state.concat(action.message);
    default:
      return state;
  }
};
1 Like

That’s the ES6 default parameter syntax. state will only be an empty array if nothing else is passed to it.