An interesting promise use case | Handling user interactions
Published: 2024-06-15 13:33:36

What are the use cases that come to our mind when we hear of promises?

1. Handling async operations.
1. Handling some task that will finish in future.
1. Doing something like network or DB calls.

But that's not all to it, we can use it to handle user interactions as well. Let us see how.


## Motivation
So, I was building simple confirmation modal for my React project. It needed to be as simple as possible. A modal with some confirmation text in it and two buttons for accepting or declining. Something like this

![Delete modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qwnwh3rv5lcposmi85g9.png)


## The simple/straight-forward approach
1. Make modal component. 
1. Mount it conditionally using state.
1. Handle delete operation inside Modal component.

The code for it looks something like 

```js
import { useState } from "react";

const Modal = ({ setShowModal, handleDelete }) => {
  return (
    <dialog open>
      <p>Are you sure you want to delete?</p>
      <button
        onClick={() => {
          setShowModal(false);
          handleDelete();
        }}
      >
        Yes
      </button>
      <button
        onClick={() => {
          setShowModal(false);
        }}
      >
        No
      </button>
    </dialog>
  );
};
function App() {
  const [showModal, setShowModal] = useState(false);
  const handleDelete = () => {
    //perform delete operation here...
    console.log("hey");
  };
  return (
    <div>
      {showModal && (
        <Modal setShowModal={setShowModal} handleDelete={handleDelete} />
      )}
      <button onClick={() => setShowModal(true)}>Delete</button>
    </div>
  );
}

export default App;
```


## Did you notice the problem?
The above code works all fine, however there are few issues 
1. We need to maintain a state for showing/hiding modal and pass the setter function to modal.
1. We need to pass the business logic to the modal(delete handler).
1. The flow of code is not linear anymore, the deletion is being handled by some other component away from the main component(App)
1. Not clean code.

## The idea of asynchronicity
It was this moment when I felt there must be a better way to handle this. I noticed that a click operation by user is also an async operation! It can happen anytime in future. This is where the idea of Promise kicked in.

## The better way
1. We can make some custom hook from where a promise is returned which can be awaited upon.
1. The promise can resolve to either true or false which can show if the user accepts or rejects.
1. The custom hook can also return a Modal component which can be directly use in at the place of application.
1. We can also make custom hook configurable to accept different messages.

## A Custom hook
```js
import { useState } from "react";

const useConfirmation = () => {
  const [modalState, setModalState] = useState({
    showModal: false,
    resolve: null,
    message: "",
  });

  const Modal = () => {
    return (
      <dialog open={modalState.showModal}>
        <div>
          {modalState.message}
          <button
            onClick={() => {
              setModalState((prev) => ({
                ...prev,
                showModal: false,
              }));
              modalState.resolve(false);
            }}
          >
            Close
          </button>
          <button
            onClick={() => {
              setModalState((prev) => ({
                ...prev,
                showModal: false,
              }));
              modalState.resolve(true);
            }}
          >
            Confirm
          </button>
        </div>
      </dialog>
    );
  };
  const confirm = (message) => {
    return new Promise((resolve) => {
      setModalState((prev) => ({
        resolve: resolve,
        showModal: true,
        message: message,
      }));
    });
  };
  return { Modal, confirm };
};

export { useConfirmation };
```
The Modal component has it's own state which stores the message, resolve function returned by promise and show state.  

## Application
```js
import { useConfirmation } from "./useConfirmation.jsx";

function App() {
  const { Modal, confirm } = useConfirmation();
  const handleDelete = async () => {
    const isItOkToDelete = await confirm("Are you sure you want to delete?");
    console.log(isItOkToDelete);
  };
  return (
    <div>
      {Modal()}
      <button onClick={handleDelete}>Delete</button>
    </div>
  );
}

export default App;
```
The `useConfirmation` hook returns a function which returns a promise. The function also takes in a message argument to display inside modal. We can await this promise to either receive true/false and proceed with the code flow ahead. 
{% codesandbox cxkqg6 %}





## Thank You
Please do share you feedback and comments. Hope you like it, have a good day.