With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.
In this article, we’ll look at how to dispatch actions asynchronously.
Async Actions
In JavaScript, a lot of things have to be done asynchronously to avoid blocking the main execution thread.
Redux can dispatch asynchronous actions so that we don’t always have to change states synchronously.
To do this, we use the Redux-Thunk middleware. We can apply middlewares by using Redux’s applyMiddleware
function.
With that, we can pass in functions that call dispatch
instead of plain objects. We need this capability to run async actions that call dispatch
and populate the store with it.
We can do this as follows:
import { createStore, applyMiddleware } from "redux";
import thunkMiddleware from "redux-thunk";
function jokeReducer(state = {}, action) {
switch (action.type) {
case "SET_JOKE":
return action.joke;
default:
return state;
}
}
let store = createStore(jokeReducer, applyMiddleware(thunkMiddleware));
function fetchJoke() {
return async dispatch => {
const response = await fetch("[https://api.icndb.com/jokes/random](https://api.icndb.com/jokes/random)");
const joke = await response.json();
dispatch({ type: "SET_JOKE", joke });
};
}
(async () => {
await store.dispatch(fetchJoke());
console.log(store.getState().value.joke);
})();
In the code above, we have the jokeReducer
which is the same as what we have before.
Then in to create the store, we write:
let store = createStore(jokeReducer, applyMiddleware(thunkMiddleware));
The difference from stores that only take plain object actions is that we have the applyMiddleware
function where we passed in the thunkMiddleware
.
The thunkMiddleware
lets us pass in functions to dispatch instead of a plain object without it.
In the function we pass in, we can call dispatch
with plain objects to do the synchronous actions.
Then we defined the fetchJoke
function, which is or action creator, as follows:
function fetchJoke() {
return async dispatch => {
const response = await fetch("[https://api.icndb.com/jokes/random](https://api.icndb.com/jokes/random)");
const joke = await response.json();
dispatch({ type: "SET_JOKE", joke });
};
}
In this function, we returned an async function that has the Redux dispatch
function as the parameter.
Then once we get the joke with the Fetch API, we call dispatch
provided in the parameter.
This way the Thunk middleware can call dispatch
in the returned function.
We can return any function, but we need to use thunks for async functions since they don’t return plain objects.
Ordinary action creators must return plain objects, but if we use the Redux Thunk middleware, we can return a function that calls dispatch
and getState
.
Then we dispatch our async action and get the value from it as follows:
(async () => {
await store.dispatch(fetchJoke());
console.log(store.getState().value.joke);
})();
All we did above was call dispatch
with the promise that the fetchJoke
function returned as we defined above. Then we use store.getState().value.joke
to get the joke’s value from the store.
Photo by Sincerely Media on Unsplash
Checking State Before Dispatching Synchronous Actions in Our Async Action Creator
We can write a function to check the state before getting data. To do this, we can make the following changes while keeping everything else the same:
function shouldFetchJoke(state) {
return !state.value || !state.value.joke;
}
function fetchJoke() {
return async (dispatch, getState) => {
if (shouldFetchJoke(getState())) {
const response = await fetch("[https://api.icndb.com/jokes/random](https://api.icndb.com/jokes/random)");
const joke = await response.json();
dispatch({ type: "SET_JOKE", joke });
}
};
}
In the code above, we defined the shouldFetchJoke
function which checks the state.value
and state.value.joke
to see if the value has been set.
Then we change fetchJoke
to call shouldFetchJoke
. Then we take advantage of the getState
parameter to get the state and check if a joke already exists in the store with shouldFetchJoke
.
If not, then we proceed to get the joke.
Conclusion
With the Redux Thunk middleware, we can pass in actions that aren’t plain objects to dispatch
.
To use it, we have to call applyMiddleware
with the thunkMiddleware
as the argument.
Then we can create an action creator that returns a function with the dispatch
and getState
functions as the first and second parameter respectively, then we can get the state with getState
as usual.