DEV Community

Cover image for An interesting promise use case | Handling user interactions
Vishal Gaurav
Vishal Gaurav

Posted on

An interesting promise use case | Handling user interactions

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

  1. Handling async operations.
  2. Handling some task that will finish in future.
  3. 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

The simple/straight-forward approach

  1. Make modal component.
  2. Mount it conditionally using state.
  3. Handle delete operation inside Modal component.

The code for it looks something like

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;
Enter fullscreen mode Exit fullscreen mode

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.
  2. We need to pass the business logic to the modal(delete handler).
  3. The flow of code is not linear anymore, the deletion is being handled by some other component away from the main component(App)
  4. 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.
  2. The promise can resolve to either true or false which can show if the user accepts or rejects.
  3. The custom hook can also return a Modal component which can be directly use in at the place of application.
  4. We can also make custom hook configurable to accept different messages.

A Custom hook

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 };
Enter fullscreen mode Exit fullscreen mode

The Modal component has it's own state which stores the message, resolve function returned by promise and show state.

Application

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;
Enter fullscreen mode Exit fullscreen mode

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.

Thank You

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

Top comments (0)