I want to show a toast when my client side component mounts.
I'm using sonner library to show toast, it's working fine when we use button to show toast.
I make an example app to show the problem. Here is the github link https://github.com/saifion33/Nextjs-toast-problem
I'm trying to trigger a toast when component mount on client side.
app/layout.tsx
<html lang="en">
  <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
    {children}
    <ToasterComp />
  </body>
</html>
ToasterComp
"use client"
import { Toaster } from "sonner"
const ToasterComp = () => {
  return (
    <Toaster closeButton richColors duration={3000} />
  )
}
export default ToasterComp
app/page.tsx
import MyComponent from "@/components/MyComponent";
export default function Home() {
  return (
    <div className="text-center">
      <h1 className=" my-10 text-blue-500 text-3xl">Sonner render problem example app</h1>
      <p className="text-slate-800">
        Reload this page, if you don't see a toast then this is not working. if you click the button you will see a toast.
      </p>
      <MyComponent />
    </div>
  );
}
MyComponent
"use client"
import { useEffect } from "react"
import { toast } from "sonner"
const MyComponent = () => {
  useEffect(() => {
    toast.success("This is the toast that will be shown.")
  }, [])
  return (
    <div>
      <button
        className="bg-blue-500 text-stone-50 border-2 border-slate-900 py-2 px-4 rounded-lg mt-4"
        onClick={() => toast.info('You clicked the button.')}
      >
        Show toast
      </button>
    </div>
  )
}
export default MyComponent
According to documentation:
To render a toast on initial page load it is required that the function
toast()is called inside of asetTimeoutorrequestAnimationFrame.
Update to dispatch the toast in a timeout:
useEffect(() => {
  const timerId = setTimeout(() => {
    toast.success("This is the toast that will be shown.");
  });
  return () => {
    clearTimeout(timerId);
  };
}, []);
In the case that you render your React application into a React.StrictMode component that will double-mount the components and run certain lifecycle methods and hook callbacks twice and dispatch two toasts (!!), you can use a React Ref to track that you've already dispatched the mounting toast.
Example:
const mountedRef = useRef();
useEffect(() => {
  let timerId;
  if (!mountedRef.current) {
    setTimeout(() => {
      toast.success("This is the toast that will be shown.");
    });
  }
  mountedRef.current = true;
  return () => {
    clearTimeout(timerId);
  };
}, []);
Note that it is currently generally considered a React anti-pattern to use React refs to "track" when a component mounts to conditionally apply logic, a useEffect hook cleanup function should be returned to unsubscribe/cancel/cleanup up any pending/asynchronous logic. I believe this is a valid edge case since this sonner library doesn't export/include any way to cancel the dispatched toast from the first "initial render", so you'll need to not dispatch the toast on the second "initial render".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With