How to render multiple notifications with help of notistack in react?

2k Views Asked by At

I'm trying to use React's 'notistack' module to display several notifications as a stack. However, it appears that I am making a mistake, as Whenever I receive a warning:

react_devtools_backend.js:3973 Warning: Cannot update during an existing state transition (such as within render)

I'm using the state here to set the Response messages(they are coming from api), which are an array of notifications. Once the alerts have been rendered, I should also make the state of the Response messages an empty array.

renderPage.js

import React, { useState, useContext } from "react";
import axios from "axios";

import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";

import { SnackbarProvider } from "notistack";

import Zoom from "@material-ui/core/Slide";

import Notification from "../../components/Notification";
import { handleResponse } from "../../services/responseHandler";
import { SelectedRunnerContext } from "./RunnersPage";

export function RunnersForm() {
    const { selected } = useContext(SelectedRunnerContext);
    const [responseMessages, setResponseMessages] = useState([]);
    const notistackRef = React.createRef();
    const onClickDismiss = (key) => () => {
        notistackRef.current.closeSnackbar(key);
    };

    const MakePostRequest = (event) => {
        event.preventDefault();
        setResponseMessages([]);
        const data = {
            selected_runners: selected,
        };

        const requestOptions = {
            method: "POST",
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json",
            },
            body: data,
        };
        axios
            .post("/messages", requestOptions)
            .then((response) => {
                const result = handleResponse(response.data);
                setResponseMessages(result);
            })
            .catch((error) => {
                console.log(error);
            });
    };

    return (
        <>
            <Button onClick={MakePostRequest}>Post</Button>
            {!!responseMessages.length && (
                <SnackbarProvider
                    maxSnack={4}
                    ref={notistackRef}
                    dense
                    preventDuplicate
                    anchorOrigin={{
                        vertical: "bottom",
                        horizontal: "right",
                    }}
                    TransitionComponent={Zoom}
                    sx={{
                        width: 700,
                    }}
                    style={{
                        fontSize: 15,
                        fontWeight: 700,
                    }}
                    action={(key) => (
                        <Button onClick={onClickDismiss(key)}>
                            <Typography
                                variant="subtitle2"
                                style={{
                                    fontWeight: 600,
                                    fontSize: 16,
                                    color: "#00579b",
                                }}
                            >
                                Dismiss
                            </Typography>
                        </Button>
                    )}
                >
                    <Notification messages={responseMessages} />
                </SnackbarProvider>
            )}
        </>
    );
}

Notification.js

import React, { Fragment } from "react";
import { useSnackbar } from "notistack";

export default function Notification(props) {
    const { enqueueSnackbar } = useSnackbar();
    const { messages } = props;
    const options = {
        variant: "success",
        autoHideDuration: 6000,
        transitionDuration: { enter: 400, exit: 400 },
    };

    messages.forEach((msg) => {
        enqueueSnackbar(msg, options);
    });
    return <></>;
}

1

There are 1 best solutions below

0
On

I've solved the issue by wrapping up the App with the Notification provider:

import React from "react";
import { useSnackbar } from "notistack";
import Button from "@mui/material/Button";
import { SnackbarProvider } from "notistack";
import Typography from "@mui/material/Typography";

function MakeGlobal() {
    const { enqueueSnackbar } = useSnackbar();
    window.enqueueSnackbar = enqueueSnackbar;
    return null;
}

export function displayNotification(messages) {
    const options = {
        variant: "success",
        autoHideDuration: 6000,
        transitionDuration: { enter: 400, exit: 400 },
    };

    messages.forEach((msg) => {
        window.enqueueSnackbar(msg, options);
    });
}

export function Provider({ children }) {
    const notistackRef = React.createRef();
    const onClickDismiss = (key) => () => {
        notistackRef.current.closeSnackbar(key);
    };
    return (
        <SnackbarProvider
            maxSnack={4}
            ref={notistackRef}
            dense
            preventDuplicate
            anchorOrigin={{
                vertical: "bottom",
                horizontal: "right",
            }}
            sx={{
                width: 700,
            }}
            style={{
                fontSize: 15,
                fontWeight: 700,
            }}
            action={(key) => (
                <Button onClick={onClickDismiss(key)}>
                    <Typography
                        variant="subtitle2"
                        style={{
                            fontWeight: 600,
                            fontSize: 16,
                            color: "#00579b",
                        }}
                    >
                        Dismiss
                    </Typography>
                </Button>
            )}
        >
            <MakeGlobal />
            {children}
        </SnackbarProvider>
    );
}

App.js

function App() {
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <BrowserRouter>
            <snackbar.Provider>
                <AppRoutes />
                <CssBaseline />
            </snackbar.Provider>
        </BrowserRouter>
         
    );