Creating a Reusable Snackbar Component in Next.js

Creating a Reusable Snackbar Component in Next.js

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.