Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Material UI - Snackbar closes when Dialog closes but its not supposed to

Material ui dialog closes the snackbar along with it.

This is a weird problem so I created a demo to demonstrate the issue:

https://codesandbox.io/s/react-hooks-counter-demo-v20w3

I am passing states from parent to child so the parent state can update based on the child

 <Child openDialog={openDialog} setOpenDialog={setOpenDialog} />

In the child, I am using these as below

export default function Child({openDialog, setOpenDialog}) {

The button in the child is supposed to close only the dialog but it closes snackbar too.

  <button 
  onClick={() => dialogClick()}
  >Click this dialog button
  </button>

Line 12 in the child has setOpenSnack("true"); This only works when I comment out line 13 setOpenDialog(false);

  const dialogClick = (event) => {
    setMsg("This should close dialog only and open the snackbar");
    setOpenSnack(true);
    setOpenDialog(false);
  };

This behavior is only when I split it into child and parent.

In short, why does setOpenSnack(true); in the child not work?

like image 762
Kal Avatar asked Sep 10 '25 03:09

Kal


1 Answers

Move your Snackbar to your parent component so that it's not dependent on Dialog's lifecycle.

App.js

import DialogBody from "./child";

function App() {
  const [openDialog, setOpenDialog] = useState(false);
  const [openSnack, setOpenSnack] = useState(false);
  const [msg, setMsg] = useState("nothing");

  function doApiCall(formData) {
    // do your API calls here
    console.log(formData);

    // when done hide dialog, show snackbar
    setOpenDialog(false);
    setOpenSnack(true);
  }

  const fireOnClick = (event) => {
    setMsg("you clicked a button");
    setOpenDialog(true);
  };

  const handleCloseSnack = (event, reason) => {
    if (reason === "clickaway") {
      return;
    }

    setOpenSnack(false);
  };

  function Alert(props) {
    return <MuiAlert elevation={6} variant="filled" {...props} />;
  }

  return (
    <div className="App">
      <h3>click button below to open dialog</h3>

      <button onClick={() => fireOnClick()}>Click me</button>

      <Dialog open={openDialog}>
        <DialogTitle>This is a dialog</DialogTitle>
        <DialogBody doApiCall={doApiCall} />
      </Dialog>

      <Snackbar
        open={openSnack}
        autoHideDuration={6000}
        onClose={handleCloseSnack}
      >
        <Alert onClose={handleCloseSnack} severity="error">
          {msg}
        </Alert>
      </Snackbar>
    </div>
  );
}

Child.js

export default function DialogBody({ doApiCall }) {
  const [name, setName] = React.useState("");

  function onChange(event) {
    setName(event.target.value);
  }

  return (
    <div>
      <input type="text" value={name} onChange={onChange} />
      <button onClick={() => doApiCall({ name })}>
        Click this dialog button
      </button>
    </div>
  );
}

Our DialogBody component only accepts a prop called doApiCall from our parent, which is invoked by clicking the Click this dialog button.

doApiCall might be an asynchronous call to your backends API which when resolves will hide the dialog and sets the snackbar to open.

Edit React Hooks Counter Demo

like image 182
bertdida Avatar answered Sep 12 '25 17:09

bertdida