export const getPosts = () => dispatch => {
dispatch(setPostLoading());
axios
.get('/api/posts')
.then(res => {
dispatch({
type: GET_POSTS,
payload: res.data
})}
)
.catch(err =>
dispatch({
type: GET_POSTS,
payload: null
})
);
};
export const addLike = id => dispatch => {
axios
.post(`/api/posts/like/${id}`)
.then(res => {
dispatch(getPosts())
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
In my project whenever a user click on the like button of a post, addLike
function will be called with an id of that post.
If I am understanding your question correctly, you are asking why you have to initially dispatch your action, and then again inside the asynchronous action need to dispatch further actions.
How dispatch is working here?
You first dispatch your action "value" to the store by calling the addLike
action creator and dispatching the returned "value" to the store.
dispatch(addLike("123"));
Normally the action creators return an action object, e.g. a Javascript object, with type
and payload
properties.
{
type: "MY_AWESOME_ACTION",
payload: "This is my awesome payload value!",
}
However, addLike
returns a function when called, e.g. addLike("123")
returns:
(dispatch) => {
axios
.post(`/api/posts/like/${id}`) // "/api/posts/like/123"
.then(res => {
dispatch(getPosts());
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
});
);
};
In other words, the following two code snippets are the same when evaluated.
dispatch(addLike("123"));
dispatch((dispatch) => {
axios
.post("/api/posts/like/123")
.then(res => {
dispatch(getPosts());
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
});
);
});
Thunks, or asynchronous action creators, return functions instead of objects. You are dispatching a function to the store.
The Thunk middleware you added to your store when it was created intercepts actions that are functions and waits for them to settle (i.e. resolve or reject). The middleware calls this action function and passes the store's dispatch
function (and store.getState
and the Thunk middleware extraArgument
) to it so further actions can be dispatched as necessary.
Here's a pretty awesome animation that helps visualize the asynchronous data flow, borrowed from the Redux docs.
Example Thunk:
const someAsyncAction = (arg) => (dispatch, getState, extraArgument) => {
...
}
Notice there are two "dispatch" function locations, one in the UI and the other the internal dispatch the store/middleware pass.
Why getPosts() is called within dispatch parentheses?
Inside your returned addLike
action you are using the dispatch
function that is passed to it from the Thunk middleware to dispatch the other actions to the store, e.g. dispatch(getPosts());
.
Similarly getPosts
is another asynchronous action creator, returning a function that will be passed the dispatch
function from the Thunk middleware.
dispatch(getPosts());
Evaluates to
dispatch((dispatch) => {
dispatch(setPostLoading());
axios
.get('/api/posts')
.then(res => {
dispatch({
type: GET_POSTS,
payload: res.data
})}
)
.catch(err =>
dispatch({
type: GET_POSTS,
payload: null
})
);
});