I am trying to extract the logic of the Material UI v5 SnackbarAlert into a re-usable component. I have found a very similar question answered recently, however my app is using JavaScript.
I’ve attempted to adapt this to JavaScript, but I am having issues with the component re-rendering multiple times upon open /close of the Alert Snackbar.
My code so far:
// src/AlertSnackbar.jsx
import React, { useEffect, useState } from 'react'
import Snackbar from '@mui/material/Snackbar';
import MuiAlert from '@mui/material/Alert';
const Alert = React.forwardRef(function Alert(props, ref) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />;
});
export default function AlertSnackbar({message, ...otherProps}) {
const [content, setContent] = useState(undefined);
const [open, setOpen] = useState(false)
const [pack, setPack] = useState([])
const handleClose = () => {
setOpen(false);
}
//update content pack
useEffect(()=> {
message && setPack((prev) => [...prev, { message, key: new Date().getTime() }]);
}, [message])
//handle consecutive snackbars
useEffect(() => {
if (pack.length && !content) {
//set a new snack when no active snack
setContent({...pack[0]})
setPack((prev)=> prev.slice(1))
setOpen(true)
} else if (pack.length && content && open) {
//Close an active snack when a new one is added
setOpen(false)
}
}, [pack, content, open])
const handleExited = () => {
setContent(undefined);
};
return (
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose} {...otherProps}
TransitionProps={{ onExited: handleExited }} key={content?.key }
>
<Alert onClose={handleClose} severity="success" sx={{ width: '100%' }}>
<div>{content?.message}</div>
</Alert>
</Snackbar>
)
}
Usage:
// src/SomeComponent.jsx
import React, { useState } from 'react'
import { Button } from '@mui/material'
import AlertSnackbar from '../components/AlertSnackbar'
export default SomeComponent = () => {
const [snackContent, setSnackContent] = useState(<></>)
const handleTestClick = () => setSnackContent(<>Hello, world!</>);
return (
<>
<Button onClick={handleTestClick}>Test</Button>
<AlertSnackbar message={snackContent} anchorOrigin={{ horizontal: "center", vertical: "bottom" }} />
</>
)
}
Any help would be much appreciated!
2
Answers
In the end, I could get the consecutive alert snackbar to work if I wrap the alert message with React.Fragment. Using just a string did not work.
Triggering the snackbar on another page like so:
But I am unsure if using React.fragment snippets like this is valid?
With these changes, your code should work correctly. Here’s the complete AlertSnackbar component: