9

I am building a React app with several components and in at least half of them I am using React-notify and it's working properly in almost all of them except one. In this one when I trigger the toast I'm getting four toasts, one behind the other, but I believe they are not different toasts, since they have the same ID.

I found this thread https://github.com/fkhadra/react-toastify/issues/182, here the user was having the same issue as mine, the only exception is that I am not setting autoclose, he even provided a gif showing the problem:

https://i.sstatic.net/SiqRo.jpg

The solution according to this thread would be remove all <ToastContainer /> of the components and render it in the app root, which in my case is App.js. I did that, however the toasts are not being shown anymore, I don't know if I've done it right, though.

Besides that I also tried to set a custom ID and it didn't change anything.

I am using React-router-dom, maybe this is influencing in something, I couldn't find a proper answer nor in the documentation neither on any other source.

Here is simplified version of my App.js:

import Layout from './containers/Layout/Layout';

import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

import { BrowserRouter, Route, Switch } from 'react-router-dom';

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Layout>
          <Switch>
            <Route path="/clientes" exact component={ClientesControls} />
            <Route path="/adm" exact component={AdmControls} />
            <Route path="/" component={OrcConfig} />
            <ToastContainer />
          </Switch>
        </Layout>
      </BrowserRouter>
    );
  }
}

Here is a sample of the componente whose bug is being generated:

import React from 'react';

import axios from '../../../axios';

import { toast } from 'react-toastify';

const listarProdutosItens = props => {
    
    const excluirItemHandler = i => {
        
        let key = props.listaItens[i].key
        let categoria = props.listaItens[i].categoria

        axios.delete(`/adm/${categoria}/${key}.json`)
            .then(res => {
                props.fetchLista()
                notify('excluído')
            })
            .catch(error => notify('não excluído'))
    }

    const notify = (arg) => {
        if (arg === 'excluído') {
            toast.success('Produto removido com sucesso')
            console.log('TESTE')
        } else if (arg === 'não excluído') {
            toast.error('Erro ao tentar remover produto')
        }
    }

    return (
        <div className="row border-bottom mt-2">
            <button onClick={() => excluirItemHandler(i)} ></button>
            {/* <ToastContainer /> */}
        </div>
    )

}

The components that are working properly have the same sintaxe.

Any help would be very appreciated.

2
  • 3
    Move <ToastContainer /> outside of <Layout /> Commented Jun 25, 2020 at 14:52
  • 1
    I don't believe that. So simple and I couldn't see. Thank you very much, it worked great. If you want to edit your comment as an answer I'll be glad to accept it. Commented Jun 25, 2020 at 14:55

9 Answers 9

38

I was having this same problem (and my was already outside the router stuff). This probably doesn't fix the underlying issue, but what worked for me was to add a custom toast id, that is change

toast.success('Produto removido com sucesso')

to

toast.success('Produto removido com sucesso', {
    toastId: 'success1',
})

and the duplicate toasts no longer showed up.

Sign up to request clarification or add additional context in comments.

4 Comments

Fixed my issue, thanks!
This fixed my issue but how does it works ? What exactly happened by adding toastId ?
@BilalMohammad I don't know the underlying code, but this is one recommended solution from the documentation: fkhadra.github.io/react-toastify/prevent-duplicate
Just a note to anyone seeing this: I haven't investigated the underlying issue, but I'm pretty sure looking back was that we toasted in a useEffect and had React in strict mode, which renders all hooks twice.
10

Just move <ToastContainer /> outside of <Layout />

Comments

6

Move the <ToastContainer/> anywhere outside of <Switch>, because:

<Switch> is unique in that it renders a route exclusively.

Also:

All children of a <Switch> should be <Route> or <Redirect> elements. Only the first child to match the current location will be rendered.

See: https://reacttraining.com/react-router/web/api/Switch

1 Comment

Thank you. It really makes sense.
2

import the toast in your component where you have added toaster logic ex. given below:

import { toast } from 'react-toastify';
// avoid the ToastContainer to add here and the css as well

Then at the root of your application:

import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const CommonComponent = () => (
  <div>
    <ToastContainer />
    <OtherComponent />
  </div>
)

Comments

2

add toastId:

toast.success('Produto removido com sucesso', {
    toastId: 'success1',
})

Comments

1

You must also certainly check that your code does not have multiple <ToastContainer/> in different places of your application

1 Comment

This suggestion solved my problem. I thought you needed a ToastContainter in every component where you called 'toast' function. Instead, I added a single <ToastContainer /> at the root of my app, and all my toasts in children components worked great. Thank you.
1
const notify = (arg) => {
    if (arg === 'excluído') {
        toast.success('Produto removido com sucesso')
        console.log('TESTE')
    } else if (arg === 'não excluído') {
        toast.error('Erro ao tentar remover produto')
    }
}

To

const notify = (arg) => {
    if (arg === 'excluído') {
        toast.success('Produto removido com sucesso', {
        toastId: "success"        
    })
   
    } else if (arg === 'não excluído') {
        toast.error('Erro ao tentar remover produto', {
        toastId: "error"        
    })
    }
}

Just use custom toastId and it will fix your issue!

Comments

1

Just add limit={1} to ToastContainer. Like this:

<ToastContainer limit={1}>

Reference: https://fkhadra.github.io/react-toastify/limit-the-number-of-toast-displayed/

Comments

1

You Just need to control the of toaster and it will resolve the issue

<ToastContainer
         position="top-right"
         autoClose={5000}
         hideProgressBar={false}
         newestOnTop={false}
         closeOnClick
         rtl={false}
         limit={1}
         pauseOnFocusLoss
         draggable
         pauseOnHover
/>

In React Application when you called the Toaster Component. Make the Prop "autoClose" as 5000 like shown in code above. It will resolve the issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.