A generic confirmation modal with Redux, Redux Toolkit, and TypeScript

JavaScript React TypeScript

We often need to allow our users to perform various delicate operations. They often can’t be undone, which might have dire consequences. Therefore, the good idea is to prompt the user for confirmation.

Across our application, the above case might happen frequently. Creating a separate confirmation modal for each of them is far from ideal. In this article, we explore various ways to tackle this issue using React, Redux with Redux Toolkit, and TypeScript.

We focus on managing the state, and for the user interface, we use Material-UI.

A simple approach

The most straightforward approach worth noting is storing the callback of the confirm button in the store.

While it is possible, it is officially discouraged by the Redux maintainers. The same goes for storing any other non-serializable items, such as promises. Also, one of the goals of Redux Toolkit is to help provide good defaults when working with a Redux store. Therefore, storing non-serializable values in our store results in Redux Toolkits showing warnings in the console. To get rid of them, we can use the property described in the documentation.

You can also read more in this discussion on StackOverflow

If we are fine with experiencing some issues with time-travel debugging and our store not being serializable, we can go with the simple, straightforward approach.

Approach with Thunk

With Redux Thunk, we can dispatch asynchronous actions and wait for them to finish. We can use that to open a confirmation modal and wait for the user to confirm the action.

By doing the above, we no longer need to put non-serializable data into the store. Still, we write the logic of the confirmation button in the same place where we open the modal. It looks simple, and it is easy to use.

First, let’s define the state of our modal.

Feel free to add more properties, such as the description that the modal contains.

Above, we define the and properties. Let’s create a slice that contains both the reducer and the basic actions.

Redux Toolkitt uses Immer under the hood to allow us to simply mutate the object. For more information, check out the documentation.

Above, we’ve defined a set of actions that change our state. Now, let’s create an async thunk action where the magic happens.

At the beginning of the thunk action, we open up our modal with . We then return a new promise that resolves when the user either confirms the action or declines it. An important part is that we need to unsubscribe to remove the listener.

You can notice that we are using the argument in our thunk. This is because, by default, we can’t access the method in our thunk. Thankfully, we can define extra arguments that we want to have access to.

And that’s it when it comes to configuring our store.

Dispatching our actions

Now, let’s create a hook for managing the state of our confirmation modal.

Please notice that the function uses .

We also need the type as suggested in the documentation. Thanks to it, TypeScript knows that returns a promise that resolves with payload containing , or .

Since we’ve got everything we need now, let’s define a component. In this example, we use Material-UI for the sake of simplicity.

To start up the whole confirmation flow, we need to call the function.

Writing unit tests for our thunk

At first glance, our thunk might look a bit complicated. To ensure that it works properly, let’s write a unit test for it.

Above, we test all the major features of our confirmation modal thunk. All of the tests pass without issues:

Handling the loading state

There is a good chance that the action we want to invoke on confirmation is asynchronous. An idea to handle it gracefully would be to display a loading state inside of our confirmation modal. We would close it only after the asynchronous function finishes.

Feel free to add some error handling to the above solution.

Under the hood, we set the parameter in the store when the loading is initiated. We then need to handle it in our .


In this article, we’ve created a generic confirmation modal. We’ve looked into a straightforward approach that involves saving functions in the store. Since it is not perfect, we’ve developed a solution that involves thunks. Thanks to it, we’ve been able to avoid saving non-serializable data inside our store. Still, we can open the confirmation modal and react to the user input in any way we need to across our application.

Notify of
Inline Feedbacks
View all comments