Notifications and alerts are an essential part of user interaction in web applications. They inform users about successes, errors, and other significant events. Material-UI’s Snackbar component is a popular choice for displaying these brief messages. In this post, we’ll explore how to create a reusable Snackbar component in a Next.js application using React context and hooks.
Why Use a Context for Snackbar?
In complex applications, you often need to trigger notifications from many different components. Passing down props or callbacks through multiple layers of components can get messy. A more elegant solution is to use a React context. This allows any component in your application to easily display a notification without prop drilling.
Setting Up the Snackbar Context
First, we create a new context for the Snackbar in a separate file (SnackbarContext.js
):
import { createContext, useContext, useState, useCallback } from 'react';
export const SnackbarContext = createContext();
export const useSnackbar = () => useContext(SnackbarContext);
export const SnackbarProvider = ({ children }) => {
const [snackPack, setSnackPack] = useState([]);
const addSnackbar = useCallback((message, severity = 'info') => {
setSnackPack((prev) => [...prev, { message, severity, key: new Date().getTime() }]);
}, []);
return (
<SnackbarContext.Provider value={{ addSnackbar }}>
{children}
{/* Snackbar Component will be added here */}
</SnackbarContext.Provider>
);
};
This SnackbarProvider
component will wrap our application, providing the addSnackbar
function through context to any child component.
Creating the Reusable Snackbar Component
Within the SnackbarProvider
, we include the reusable Snackbar component that listens to the snackPack
state:
import { Alert, Snackbar } from '@mui/material';
// ... inside SnackbarProvider component
{snackPack.map((snack, index) => (
<Snackbar
key={snack.key}
open
autoHideDuration={6000}
onClose={() => {
setSnackPack((prev) => prev.filter((item) => item.key !== snack.key));
}}
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
>
<Alert onClose={() => {
setSnackPack((prev) => prev.filter((item) => item.key !== snack.key));
}} severity={snack.severity} sx={{ width: '100%' }}>
{snack.message}
</Alert>
</Snackbar>
))}
Each message in the snackPack
array is displayed as a Snackbar. We use the key
property to uniquely identify each message, which is helpful for dismissing messages correctly.
Integrating SnackbarProvider in Your Application
In your Next.js _app.js
file, wrap your application with the SnackbarProvider
:
import { SnackbarProvider } from '../path/to/SnackbarContext';
function MyApp({ Component, pageProps }) {
return (
<SnackbarProvider>
<Component {...pageProps} />
</SnackbarProvider>
);
}
export default MyApp;
Using the useSnackbar Hook
Anywhere in your application, you can now use the useSnackbar
hook to trigger Snackbar messages:
import { useSnackbar } from '../path/to/SnackbarContext';
const MyComponent = () => {
const { addSnackbar } = useSnackbar();
const handleAction = () => {
addSnackbar('This action was successful!', 'success');
};
return (
// Your component JSX
);
};
Conclusion
This approach simplifies the process of displaying notifications in a Next.js application. By using a context provider, we can avoid prop drilling and make our notification system more maintainable and elegant.
The reusable Snackbar component makes it easy to display consistent and attractive notifications across the entire application, enhancing the user experience.