Async Actions with Redux-Thunk

Async Actions with Middleware and Thunks
Thunks
A thunk is a function used to delay an action until it's needed by the app.
Fun Fact:
thunkcomes from a play on the word “think” but in the past tense.
In JavaScript, functions are thunks! They hold a computation and they can be executed at any time and/or passed along to other functions, whom if they choose to, can be executed at any time. A common practice is for thunks to be returned by a higher order function. The returned thunk contains the process that is to be delayed until needed. For Example:
const orderPizza = () => console.info('Send Order')
orderPizza();
const getOrderStatusThunk = () => {
return () => {
console.info('Getting Status');
}
const getFinalStatus = getOrderStatusThunk();
getFinalStatus();
Thunks in Redux
A bit of data for comparison:

In Redux, thunks can be used to hold asynchronous logic that interacts with the store. When thunks are dispatched to the store, their enclosed asynchronous computations are evaluated first, then sent off to the store.
The arguments passed into thunks are dispatch and getState, both coming from the store itself. This allows actions to be dispatched or for the state to be referenced within it's contained logic. They help in moving complex logic out of components or hooks along with interacting with any Redux store.
Middleware In Redux
Redux middleware extends the store’s abilities and lets you write asynchronous logic that can interact with the store. Middleware is added to the store either through createStore() or configureStore(). The redux-thunk package is a popular tool when using middleware in a Redux application.
Redux Thunk Middleware
The redux-thunk middleware package allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action or to dispatch only if a certain condition is met.
thunk middleware:
// standard middleware definition, with 3 nested functions:
// 1) Accepts `{dispatch, getState}`
// 2) Accepts `next`
// 3) Accepts `action`
const thunkMiddleware =
({ dispatch, getState }) =>
next =>
action => {
// If the "action" is actually a function instead...
if (typeof action === 'function') {
// then call the function and pass `dispatch` and `getState` as arguments
return action(dispatch, getState)
}
// Otherwise, it's a normal action - send it onwards
return next(action)
}
action creators:
import { fetchTodos } from '../actions';
const fetchTodosThunk = (
dispatch,
getState
) => {
setTimeout(
dispatch(fetchTodos()),
5000);
};
/*
redux-thunk allows the returned
thunk to be dispatched
*/
store.dispatch(fetchTodosLater());
Thunk middleware pairs perfectly with Redux since it's not making Redux do something it doesn't want to. Thunks help repeate the idea of currying. In fact, the redux-thunk package has been included in the Redux-Toolkit.
Currying is breaking down a function that takes multiple arguments into a series of functions that each take only one argument.
Creating an Async Thunk
import { createAsyncThunk } from '@reduxjs/toolkit';
import { userAPI } from './userAPI';
const fetchUser = createAsyncThunk(
'users/fetchByIdStatus',
async (user, thunkAPI) => {
const response = await userAPI.fetchById(user.id);
return response.data;
}
);
const user = {username: "coder123", id: 3};
store.dispatch(fetchUser(user))
Creating a Slice of the Store
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { client } from '../api';
const initialState = {
pizzas: [],
status: 'idle'
};
export const fetchPizzas = createAsyncThunk('pizzas/fetchPizzas', async () => {
const { pizzas, err } = await client.get('/api/v2/pizzas');
if (err) {
throw err;
};
return pizzas
});
const pizzasSlice = createSlice({
name: 'pizzas',
initialState,
reducers: {
addPizza: (state, action) => {
state.pizzas.push(action.payload);
}
},
extraReducers: {
[fetchPizzas.pending]: (state, action) => {
state.status = 'in preperation';
},
[fetchPizzas.fulfilled]: (state, action) => {
state.status = 'delivered';
state.pizzas = state.pizzas.concat(action.payload);
}
}
});
Thats it for now :-)