material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

[Dialog] Add imperative methods to display them directly

Open CarbonPool opened this issue 3 years ago • 6 comments

Refer to the call and implementation of the ant-design dialog box. This solution brings more flexibility and concise code.

Will there be such a solution?

import { Dialog } from "@material-ui/core";

Dialog.show({
  type: "info",
  title:  "Message",
  content: "Hello",
  onOk: () => { ... }
});

Benchmark

  • https://ant.design/components/modal/#components-modal-demo-hooks
  • http://bootboxjs.com/
  • https://dev.to/dmtrkovalenko/the-neatest-way-to-handle-alert-dialogs-in-react-1aoe

CarbonPool avatar Feb 03 '21 13:02 CarbonPool

Could you expand a bit on how you would use it and why the existing API cannot be used for that use case?

Offering an imperative API for state updates can be quite problematic since we or React is no longer in control of the semantics of such an update. So these APIs impose quite the maintenance burden and it's not clear why it is needed considering this is a React library.

eps1lon avatar Feb 03 '21 13:02 eps1lon

Could you expand a bit on how you would use it and why the existing API cannot be used for that use case?

Offering an imperative API for state updates can be quite problematic since we or React is no longer in control of the semantics of such an update. So these APIs impose quite the maintenance burden and it's not clear why it is needed considering this is a React library.

Example: https://ant.design/components/modal/

In many scenarios, the notification dialog needs to be called repeatedly to avoid introducing too many <Diglog>{children}</Dialog> in the component render, but according to different states, the confirmation button flexibly controls the callback function. This idea comes from most systems API.

CarbonPool avatar Feb 03 '21 13:02 CarbonPool

In many scenarios, the notification dialog needs to be called repeatedly to avoid introducing too many <Diglog>{children}</Dialog> in the component render

Could you describe these scenarios in detail? I'm not following why this API is required to display a single dialog instead of multiple ones.

eps1lon avatar Feb 03 '21 14:02 eps1lon

Could you expand a bit on how you would use it and why the existing API cannot be used for that use case? Offering an imperative API for state updates can be quite problematic since we or React is no longer in control of the semantics of such an update. So these APIs impose quite the maintenance burden and it's not clear why it is needed considering this is a React library.

Example: https://ant.design/components/modal/

In many scenarios, the notification dialog needs to be called repeatedly to avoid introducing too many <Diglog>{children}</Dialog> in the component render, but according to different states, the confirmation button flexibly controls the callback function. This idea comes from most systems API.

To achieve scenario you can be use library such as toastify or notistack. Even notistack is build with material UI .. https://iamhosseindhv.com/notistack (Simply use custom snackback)

Sandeep06Dev avatar Feb 03 '21 14:02 Sandeep06Dev

Thanks for opening this issue. I thought that we already had an open issue for this pain point. The equivalent issue for the Snackbar is #18098. I have updated the issue's description with the benchmark I have been doing on this for a year or two (I didn't find much).

oliviertassinari avatar Feb 03 '21 21:02 oliviertassinari

@CarbonPool most likely you want imperative handler(s) to be set on the instance of the dialog component rather than relying on static methods, for example:

import * as React from "react";
import { Button, Container } from "@mui/material";
import { ConfirmDialog, DialogElement } from "./ConfirmDialog.js";

export function Example(): JSX.Element {
  const dialogRef = React.useRef<DialogElement>(null);

  return (
    <Container>
      <Button onClick={() => dialogRef.current?.open()}>Show Dialog</Button>
      
      <ConfirmDialog ref={dialogRef} onConfirm={...} />
    </Container>
  );
}

@oliviertassinari BTW, it might be a good idea to add .open() method to the Dialog's ref out of the box which should be a small tweak without any breaking changes.

https://github.com/kriasoft/react-starter-kit/discussions/2004


Alternatively, with <DialogProvider> and useDialog() hook, it may look like this:

import * as React from "react";
import { Button, Container } from "@mui/material";
import { useDialog } from "./core/dialog.js";
import { ConfirmDialog } from "./dialogs/ConfirmDialog.js"; // Custom dialog based on Material UI <Dialog />

export function Example(): JSX.Element {
  const dialog = useDialog(
    // factory method returning an instance of Material UI dialog
    () => <ConfirmDialog onConfirm={...} />, // `open`, and `onClose` props  will be added by the hook
    [] // React hook dependencies
  );

  return (
    <Container>
      <Button onClick={dialog.show}>Show Dialog</Button>
    </Container>
  );
}

By default, the DialogProvider can mount a single instance of the target dialog when used on multiple screens, and if a new instance of the dialog is needed, it can be done by passing key={...} with a unique value to the dialog props.


Alternatively, the useDialog() hook can operate without a need to add <DialogProvider> upstream like this:

import * as React from "react";
import { Button, Container } from "@mui/material";
import { useDialog } from "./core/dialog.js";
import { ConfirmDialog } from "./dialogs/ConfirmDialog.js"; // Custom dialog based on Material UI <Dialog />

export function Example(): JSX.Element {
  const dialog = useDialog(
    // factory method returning an instance of Material UI dialog
    () => <ConfirmDialog onConfirm={...} />, // `open`, and `onClose` props  will be added by the hook
    [] // React hook dependencies
  );

  return (
    <Container>
      <Button onClick={dialog.show}>Show Dialog</Button>
      {dialog.component}
    </Container>
  );
}

koistya avatar Sep 17 '22 15:09 koistya

The Toolpad team is exploring imperative APIs for interacting with dialogs. If this is something that interests you, I invite you to read and comment on the RFC.

Toolpad Core is new set of abstractions we're creating to help you build internal and B2B applications faster

Janpot avatar May 31 '24 10:05 Janpot