Using Custom Middleware for Async Actions
When working with Redux, actions are typically plain objects with a type property that describes the action and payload that might contain additional data. However, sometimes actions need to perform asynchronous operations, such as making API calls, and that’s when custom middleware comes into play.
Custom middleware intercepts actions before they reach the reducers, allowing you to handle async operations and dispatch additional actions when the async operation has completed.
Let’s take a look at an example to understand it better:
// Define your custom middleware function
const asyncMiddleware = (store) => (next) => (action) => {
if (typeof action === 'function') {
// If the action is a function, execute it with the store's dispatch function
return action(store.dispatch, store.getState);
}
// If the action is not a function, let it continue to the next middleware or reducer
return next(action);
};
// Create your Redux store with applyMiddleware
const store = createStore(
rootReducer,
applyMiddleware(asyncMiddleware)
);
// Define an async action creator
const fetchUser = () => async (dispatch, getState) => {
dispatch({ type: 'FETCH_USER_REQUEST' });
try {
const response = await fetch('/api/user');
const user = await response.json();
dispatch({ type: 'FETCH_USER_SUCCESS', payload: user });
} catch (error) {
dispatch({ type: 'FETCH_USER_FAILURE', payload: error.message });
}
};
// Dispatch the async action to trigger the middleware
store.dispatch(fetchUser());
// The asyncMiddleware intercepts the action, recognizes it as a function, and executes it with dispatch and getState
// The dispatch function is used to dispatch the loading, success, and error actions based on the API response
In this example, we define a custom middleware function called asyncMiddleware. This function takes the store as an argument and returns another function that takes next as an argument. This returned function takes an action as an argument and checks if it is a function. If it is a function, it executes the function with the store’s dispatch and getState functions. If it is not a function, it lets the action continue to the next middleware or reducer.
Next, we create our Redux store using createStore and applyMiddleware. We pass our asyncMiddleware function to applyMiddleware to apply it to the store’s dispatch process.
Then, we define an async action creator called fetchUser. This action creator returns an async function that takes dispatch and getState as arguments. In this async function, we dispatch a loading action, make an API call using fetch, and dispatch success or failure actions based on the API response.
Finally, we dispatch the fetchUser action. The asyncMiddleware intercepts the action, recognizes it as a function, and executes it with dispatch and getState. This allows us to handle asynchronous operations and dispatch additional actions as needed.