Search code examples
javascriptreactjssnackjs

Dismiss Snackbar Onclick of React Alert component


I have a React Snackbar component that I have called in a parent component and I passed props based on the severity, message and open to the Snackbar component. I am able to access the props in the child Snackbar component. However, when dismissing the Snackbar or trying to close it, I get the error TypeError: setOpen is not a function.

 export default function MessageSnackbars(props) {
 const classes = useStyles();
 const [setOpen] = React.useState(false);
 const message = props.message;
 const severity = props.severity;
 const open = props.open;

 const handleClose = (event, reason) => {
    if (reason === 'clickaway') {
    return;
 }

setOpen(false);
};

return (
<div className={classes.root}>
  <Snackbar
    autoHideDuration={6000}
    onClose={handleClose}
    open={open}
  >
    <Alert
      onClose={handleClose}
      severity={severity}
    >
      {message}
    </Alert>
  </Snackbar>
</div>
);
}

Solution

  • The first item in the array is the state and the second item is the state updater function.

    So

    const [setOpen] = React.useState(false);
    

    is supposed to be

    const [ ,setOpen] = React.useState(false);
    

    Also you are relying on the open from the props, to handle the state of the snackbar component ( open/close ). So unless the props.open is updated in the parent, it would not really close the component.

    One other way would be is to keep the props.open in sync within the component which would work as expected.

    export default function MessageSnackbars(props) {
      const classes = useStyles();
      const {message, severity, open} = props;
      // Uses props.open to keep track of the open state 
      const [isLocalOpen, setIsLocalOpen] = React.useState(open);
    
      // Used to keep the props.open in sync
      // as part of the local state
      useEffect(() => {
        setIsLocalOpen(open);
      }, [open]);
    
      const handleClose = (event, reason) => {
        if (reason === 'clickaway') {
          return;
        }
    
        setIsLocalOpen(false);
      };
    
      return (
        <div className={classes.root}>
          <Snackbar autoHideDuration={6000} onClose={handleClose} open={isLocalOpen}>
            <Alert onClose={handleClose} severity={severity}>
              {message}
            </Alert>
          </Snackbar>
        </div>
      );
    }