Importantly, reducers are always synchronous. So a reducer shouldn't receive a promise. Actions should only consist of plain data and take the following form:
{
type: 'ADD_TODO',
payload: {
text: 'Do something.'
}
}
redux-promise allows us to put a promise in the payload of an action.
Once redux-promise is added to the middleware chain we can dispatch actions which have a promise in their payload property.
The redux-promise middleware will then handle this action before it reaches the store and dispatches any further actions once the promise has been resolved or rejected and the payload will consist of the response or error in each case.
These further actions that are dispatched by redux-promise once the promise has been resolved or rejected are synchronous just like any action that is dispatched. Remember the job of our middleware is to dispatch additional actions after the promise in the action payload has resolved or rejected.
Dispatch Action --> Middleware (redux-promise dispatches further actions) --> reducers get the error or data from these further actions --> Store updated by reducers
Here is a self-contained example where we will make a request for data on a movie to the open movie database api to demonstrate how redux-promise works.
On to the store first
store.js
import { createStore, combineReducers, applyMiddleware } from 'redux'
import promiseMiddleware from 'redux-promise'
let rootReducer = combineReducers(reducers)
let store = createStore(
rootReducer,
applyMiddleware(promiseMiddleware)
)
Now we need pass Redux's applyMiddleware function as an argument to create store and in turn provide redux-promise as an argument to applyMiddleware.
Now the action creator.
When the action creator function is called below the axios request will be made. This request will return a promise which will then be passed through our redux-promise middleware.
actions/index.js
export function requestMovie(movieTitle) {
const url = `http://www.omdbapi.com/??=${movieTitle}&y=&plot=short&r=json`
return {
type: 'REQUEST_MOVIE',
payload: axios.get(url)
}
}
Our reducer will then be given the the result of our promise.
The main function handles the action that is dispatched by the redux-promise middleware after a promise has been rejected or resolved
reducers/index.js
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
movies: movies,
err: err
});
function err(err = false, action){
switch (action.type) {
case 'REQUEST_MOVIE':
return(action.payload.response.status !== 200)
}
return err;
}
function movies(movies = [], action){
switch (action.type) {
case 'REQUEST_MOVIE':
if(action.payload.response.status === 200){
return [...movies, action.payload.response.data]
} else{
return [movies]
}
}
return movies
}
export default rootReducer;