The neatest way to handle alert dialogs in React

The neatest way to handle alert dialogs in React

The neatest way to handle alert dialogs in React

Originally published by Dmitriy Kovalenko at dev.to

Hola! Lazy dev here and we will talk about handling dialog alerts in react without tears 😢. If you are tired of tons of copy-pastes just to create new freaking «one question» modal dialog — prepare your coffee we are starting.

The goal

We want to make the neatest solution for displaying an alert. Pretty similar to what we have in a browser with a native alert function.

const isConfirmed = alert("Are you sure you want to remove this burrito?");

if (isConfirmed) { await api.deleteThisAwfulBurrito(); }

Sneak peek

Finally we will get to something like this.

const YourAwesomeComponent = () => {
  const confirm = useConfirmation()

confirm({ variant: "danger", title: "Are you sure you want to remove this burrito?", description: "If you will remove this burrito you will regret it 😡!!" }).then(() => { api.deleteThisAwfulBurrito(); }); }

Interested? Let's write some code.

First of all, we need to start with creating actually the modal dialog. This is just a simple alert dialog built with ❤️ and material-ui

import {
  Button,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText,
  DialogActions,
} from "@material-ui/core";

export const ConfirmationDialog = ({ open, title, variant, description, onSubmit, onClose }) => { return ( <Dialog open={open}> <DialogTitle>{title}</DialogTitle> <DialogContent> <DialogContentText>{description}</DialogContentText> </DialogContent> <DialogActions> <Button color="primary" onClick={onSubmit}> YES, I AGREE </Button> <Button color="primary" onClick={onClose} autoFocus> CANCEL </Button> </DialogActions> </Dialog> ); };

OK, but how we will adopt it to be working dynamically? That's an interesting thing to consider. Why do we need a lot of dialogs for each component if the user can see only one alert dialog simultaneously?

If you are showing an alert dialog over the other alert dialog...you probably need to reconsider the UX part of your application.

So here we go. Everything we need is to render only 1 top-level modal at the root of our application and show it when we need to. We'll use the power of react hooks to make it looks gracefully.

Wrap the context

Let's create a new context instance and wrap our component tree with it. Also, create a simple state that will save the currently displaying options for the alert (like title, description and everything you need).

interface ConfirmationOptions {
  title: string;
  description: string;
}

const ConfirmationServiceContext = React.createContext< // we will pass the openning dialog function directly to consumers (options: ConfirmationOptions) => Promise<void> >(Promise.reject);

export const ConfirmationServiceProvider= ({ children }) => { const [ confirmationState, setConfirmationState ] = React.useState<ConfirmationOptions | null>(null);

const openConfirmation = (options: ConfirmationOptions) => { setConfirmationState(options); return Promise.resolve() };

return ( <> <ConfirmationServiceContext.Provider value={openConfirmation} children={children} />

  &lt;Dialog open={Boolean(confirmationState)} {...confirmationState} /&gt;
&lt;/&gt;

); };

Now our dialog will be opened once we connect any consumer and call the provided function.

Resolve confirmation

And now we need to somehow deal with closing dialog and getting a callback from the consumers. Here was used Promise based API, but it is possible to make it works using a callback style. In this example, once the user accepted or canceled the alert, your awaiting promise will be resolved or rejected.

To do so we need to save Promise's resolving functions and call them on appropriate user action. React's ref is the best place for that.

  const awaitingPromiseRef = React.useRef<{
    resolve: () => void;
    reject: () => void;
  }>();

const openConfirmation = (options: ConfirmationOptions) => { setConfirmationState(options); return new Promise((resolve, reject) => { // save the promise result to the ref awaitingPromiseRef.current = { resolve, reject }; }); };

const handleClose = () => { // Mostly always you don't need to handle canceling of alert dialog // So shutting up the unhandledPromiseRejection errors if (confirmationState.catchOnCancel && awaitingPromiseRef.current) { awaitingPromiseRef.current.reject(); }

setConfirmationState(null);

};

const handleSubmit = () => { if (awaitingPromiseRef.current) { awaitingPromiseRef.current.resolve(); }

setConfirmationState(null);

};

That's it! Our dialog machine is almost ready! One thing is left — create a custom hook for better readability

export const useConfirmationService = () =>
  React.useContext(ConfirmationServiceContext);

Customization

You can easily customize dialog content by passing additional variantprop. Just add it to the ConfirmationOptions

export interface ConfirmationOptions {
  variant: "danger" | "info";
  title: string;
  description: string;
}

And render different dialog content as you wish.

  <DialogActions>
    {variant === "danger" && (
      <>
        <Button color="primary" onClick={onSubmit}>
          Yes, I agree
        </Button>
        <Button color="primary" onClick={onClose} autoFocus>
          CANCEL
        </Button>
      </>
    )}

{variant === "info" &amp;&amp; (
  &lt;Button color="primary" onClick={onSubmit}&gt;
    OK
  &lt;/Button&gt;
)}

</DialogActions>

Are you ready?!

Here is the final working example. Feel free to just steal the implementation of ConfirmationService.tsx file if you want to. This is pretty standalone and isolated logic of what we were talking about.

P.S. No burritos were harmed in the making of this article


Originally published by Dmitriy Kovalenko at dev.to

=======================================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Understanding TypeScript

☞ Typescript Masterclass & FREE E-Book

☞ React - The Complete Guide (incl Hooks, React Router, Redux)

☞ Modern React with Redux [2019 Update]

☞ The Complete React Developer Course (w/ Hooks and Redux)

☞ React JS Web Development - The Essentials Bootcamp

☞ React JS, Angular & Vue JS - Quickstart & Comparison

☞ The Complete React Js & Redux Course - Build Modern Web Apps

☞ React JS and Redux Bootcamp - Master React Web Development

reactjs javascript web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Hire Web Developer

Looking for an attractive & user-friendly web developer? HourlyDeveloper.io, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

ReactJS Web App Development Services

We provide top-notch ReactJS development services to global clients. Hire expert ReactJS developers from top React JS development company, Skenix Infotech.

Why Web Development is Important for your Business

With the rapid development in technology, the old ways to do business have changed completely. A lot more advanced and developed ways are ...

Important Reasons to Hire a Professional Web Development Company

    You name the business and I will tell you how web development can help you promote your business. If it is a startup or you seeking some...

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.