I am quite new to React and Redux. I want to chain multiple API calls using redux-promise-middleware and implemented my actions as follows:
locationActions.js:
import { visitLocation } from '../services/actionService';
export const VISIT_LOCATION = 'VISIT_LOCATION';
export const VISIT_LOCATION_PENDING = 'VISIT_LOCATION_PENDING';
export const VISIT_LOCATION_FULFILLED = 'VISIT_LOCATION_FULFILLED';
export const VISIT_LOCATION_REJECTED = 'VISIT_LOCATION_REJECTED';
const visitLocationAction = (characterId, location) => ({
type: VISIT_LOCATION,
// visitLocation returns a new promise
payload: visitLocation(characterId, location)
});
export { visitLocationAction as visitLocation };
I dispatch this action from my React component using mapDispatchToProps
:
const mapDispatchToProps = dispatch => (
bindActionCreators({ visitLocation }, dispatch)
);
This works! However, I want to dispatch another action after visitLocation
is settled and fulfilled. I can not call Promise.then()
because it doesn't provide the dispatch
method, therefore not "binding" my action to the reducer.
Tutorials mention I should call dispatch(secondAction())
but I do not have dispatch available in my action creators.
Can someone point out to me what am I missing?
Edit:
As suggested in the first answer, I tried the following approach:
import { visitLocation } from '../services/locationService';
import { fetchSomething } from '../services/otherService';
const visitLocationAction = (characterId, location) => {
return (dispatch) => {
return dispatch(visitLocation(characterId, location))
.then(() => dispatch(fetchSomething()));
};
};
export { visitLocationAction as visitLocation };
But I got action:undefined and the following error:
Error: Actions must be plain objects. Use custom middleware for async actions.
at dispatch (redux.js:200)
at redux-logger.js:1
Tutorials mention I should call
dispatch(secondAction())
but I do not have dispatch available in my action creators.
Let me answer this part of your question first. As mentioned in the first answer, you need Redux Thunk, a middleware, to use dispatch
in your action creators.
By default, Redux action creators return plain objects like this:
const returnsAnObject = () => ({
type: 'MY_ACTION'
payload: ...,
meta: ....
})
With Redux Thunk, action creators can essentially return functions. A function that returns a function is called a "thunk", hence the name of Redux Thunk.
const returnsAFunction = (dispatch) => dispatch({
type: 'MY_ACTION'
payload: ...,
meta: ....
})
In the specific case of Redux Thunk, you return the dispatch
function. Redux Thunk enables you to return dispatch
by providing it as a parameter to your action creators.
But I got
action:undefined
Let's unpack this. We know--thanks to Redux Thunk--you can chain multiple actions together using dispatch
. However, as you mentioned in your edited question, you still get the "plain object" error.
Error: Actions must be plain objects. Use custom middleware for async actions.
at dispatch (redux.js:200)
at redux-logger.js:1
This is because you called dispatch
with a Promise object, not a plain object.
const visitLocationAction = (characterId, location) => {
return (dispatch) => {
return dispatch(visitLocation(characterId, location))
// Yes, it is correct to call dispatch here
// However, `dispatch` accepts plain objects, not Promise objects
.then(() => dispatch(fetchSomething()));
};
};
To fix this problem, simply modify your second dispatch to use a plain object:
const visitLocationAction = (characterId, location) => {
return (dispatch) => {
return dispatch(visitLocation(characterId, location))
.then(() => dispatch({
type: 'VISIT_LOCATION_SECOND_TIME'
payload: fetchSomething()
}));
};
};