What is the point of Redux Promise and Redux Promise Middleware?
When you call an action creator, one the very first line of the action creator function, you make the ajax request. That's a network request that is going to reach out to that JSON API.
The key part to understand is that when we make that request, we go down to the next line of code where we form up that action object and return it. The time between those two steps, between making the request and returning the action is instantaneous.
As you very well know, whenever we make a network request to some outside API, it may take some amount of time to get a response back.
So, after we return our action from the action creator, at some point in the future, we get a response back from the JSON API.
So, between Ajax request issued and Action returned from action creator may be instantaneous, but the time between Action being returned from action creator and response from JSON API received may take longer.
Regardless how long it takes, by the time the action shows up inside of the reducer, it always has our data available from our API.
To give you a better idea, I have added a debugger
statement to one of my own reducers so we can look at the different values inside of there.
import { SAVE_COMMENT, FETCH_COMMENTS } from 'actions/types';
export default function(state = [], action) {
switch (action.type) {
case SAVE_COMMENT:
return [...state, action.payload];
case FETCH_COMMENTS:
debugger;
const comments = action.payload.data.map(comment => comment.name);
return [...state, ...comments];
default:
return state;
}
}
When I clicked the Fetch Comments button thats when it called the action creator and inside my sources tab I immediately hit the debugger
statement.
Here is evidence that whenever this action shows up inside a reducer, it has the response that it got from the API.
Now, lets remove the Redux Promise middleware and see what happens.
Middleware:
export default ({ children, initialState = {} }) => {
const store = createStore(
reducers,
initialState,
applyMiddleware(reduxPromise)
);
Middleware gone:
export default ({ children, initialState = {} }) => {
const store = createStore(reducers, initialState, applyMiddleware());
return <Provider store={store}>{children}</Provider>;
};
What's this?
The payload
is not a response coming back from the JSON API, instead its a pending Promise
, which means our request is still out on the network waiting to come back from the JSON API. So clearly, without Redux Promise middleware, our application will not work as expected.
Action creators were not developed to support asynchronous request, call it an oversight, I don't know.
We use middlewares like Redux Promise to look at actions that are about to be sent to a reducer and we have the opportunity to delay, log, modify or stop the action entirely and its only through these middlewares that we make these asynchronous requests work the way we expect it to. We are using Redux Promise because we want to inspect every action returned from an action creator and if it contains an API request or some asynchronous request, we want to delay it, so we can get that response to come back before the action goes on to the reducers. That is what Redux Promise does for us.
The linked answers are correct, but I'll try to explain further.
A basic Redux store will only accept dispatching plain object actions:
store.dispatch({type : "ADD_TODO", text : "Buy milk"});
If you try to pass anything other than a plain object action, the store will throw an error:
store.dispatch(() => {});
// Error: "Actions must be plain objects. Use custom middleware for async actions."
Middleware form a pipeline around store.dispatch()
, and each middleware can do anything it wants with whatever value was passed to dispatch
: modify it, log it, delay it, or dispatch something else instead it. That means that a middleware can "teach" dispatch()
how to accept something that's not a plain action object, by intercepting the value and doing something else instead.
So, redux-thunk
"teaches" dispatch
how to accept functions, by intercepting the function and calling it instead of passing it on to the reducers. redux-promise
"teaches" dispatch
how to accept promises, by intercepting the promise and dispatching actions when the promise resolves or rejects.
Normally, dispatch
returns whatever action object was passed in. Because middleware wrap around dispatch
, they can also change what value is being returned. redux-thunk
will run the thunk function, and return whatever that thunk function returns. That lets you do useful things like return a promise from a thunk, and chain behavior from there:
dispatch(someThunkReturningAPromise())
.then(() => {
// Do more stuff here
});
For more info on the topic, see the Redux FAQ entry on dealing with side effects, and the articles in the Redux Side Effects section of my React/Redux links list.