mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
94.1k stars 32.34k forks source link

[Snackbar] Add imperative methods to display them directly #18098

Open jiangyh1024 opened 5 years ago

jiangyh1024 commented 5 years ago

Summary 💡

Support imperative calls for the sake of simplicity.

Examples 🌈

import { useSnackbar } from '@material-ui/core';

function MyComponent() {
  const snackbar = useSnackbar();

  return (
    <Button
      onClick={() => {
        snackbar({
          message: "My primary message for the user.",
          duration: 3000,
          variant: 'success',
        });
      }}
    >
      Trigger
    </Button>
  );
}
import { ConfigProvider } from '@material-ui/core';

<ConfigProvider snackbar={{ maxItems: 3 }} />

Motivation 🔦

Without such support, a developer has to set up a global event emitter system. It's cumbersome and tedious.

Benchmark

jiangyh1024 commented 5 years ago

currently I use way below to implement this but with style issue image

image

after response fails, extra style html marks are added to

image

image

jiangyh1024 commented 5 years ago

image

don't know why

oliviertassinari commented 5 years ago

@jiangyh1024 I'm 💯 onboard with you, I think that an imperative API makes a lot of sense. We recommend the usage of notistack for this problem, for now.

Follow the discussion with @leMaik in #17762 for more details. I think that we should snooze this problem for a good 6 months to see how people react.

NearHuscarl commented 4 years ago

I manage to solve a similar problem with Dialog. It's a bit easier in my case since I don't have to keep track of the key, you can just pop the top Dialog if you want to close. See my answer here for more detail. Btw, in Flutter you can already do that using showDialog which is a built-in method. Hope this will come to Material-UI soon.

kasperpeulen commented 3 years ago

Without such support, a developer has to set up a global event emitter system. It's cumbersome and tedious.

Is that true? You could write it like this, no?

export default function MyComponent() {
  const [snackbar, setSnackbar] = useState<{ message: string; duration: number }>();
  const onClose = () => setSnackbar(undefined);
  return (
    <>
      <Button
        onClick={() => {
          setSnackbar({
            message: "My primary message for the user.",
            duration: 3000,
          });
        }}
      >
        Trigger
      </Button>
      <Portal>
        <Snackbar
          open={snackbar != null}
          autoHideDuration={snackbar?.duration}
          onClose={onClose}
          message={snackbar?.message}
        ></Snackbar>
      </Portal>
    </>
  );
}
oliviertassinari commented 3 years ago

@kasperpeulen I think that your example precisely surfaces the issue. This is not enough. What happens if two Snackbar component tries to display a message? What's do we gain by writing this boilerplate, can't it be abstracted?

ggcaponetto commented 3 years ago

Maybe you want to check out the imperative Snackbar library that I built. https://github.com/ggcaponetto/mui-gotit