fkhadra / react-toastify

React notification made easy 🚀 !
https://fkhadra.github.io/react-toastify/introduction
MIT License
12.34k stars 676 forks source link

No toast shown in Nextjs 13 #963

Closed qnxdev closed 1 year ago

qnxdev commented 1 year ago

Report Bug

No toast shown

Nextjs 13

Install package Import react-toastify css in /src/app/layout.tsx Import and place it in JSX in /src/app/layout.tsx Call toast("hi) in any page.

Toast should appear

Nextjs 13 Brave browser

qnxdev commented 1 year ago

Solution: I was able to solve this by adding to the current page at /app/myPage/page.tsx

Seems like a temporary solution but fine with me

nokwin commented 1 year ago

@qnxdev You need wrap <ToastContainer />into new client component.

Here how it's done on my side

toast.provider.tsx

"use client";

import { ToastContainer } from "react-toastify";

interface ToastProviderProps {
  children: React.ReactNode;
}

export default function ToastProvider({ children }: ToastProviderProps) {
  return (
    <>
      {children}
      <ToastContainer />
    </>
  );
}

I've put <ToastProvider /> into body element

app/layout.tsx

import { getUserFromSession } from "@/actions/auth";
import Navbar from "@/components/navbar.component";
import AuthProvider from "@/providers/auth.provider";
import ToastProvider from "@/providers/toast.provider";
import Link from "next/link";
import "./globals.css";

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const user = await getUserFromSession();

  return (
    <AuthProvider user={user}>
      <html lang="en">
        <body suppressHydrationWarning>
          <ToastProvider>
            <header className="bg-amber-400 h-16 flex items-center px-4 mb-4">
              <Link href="/" className="text-2xl mr-4">
                Fast Parcel
              </Link>
              <Navbar />
            </header>
            {children}
            <footer className="text-center my-4">
              &copy; 2023 Fast Parcel
            </footer>
          </ToastProvider>
        </body>
      </html>
    </AuthProvider>
  );
}
matheusgit1 commented 10 months ago

don't forget to import toast css

` "use client"; import "react-toastify/dist/ReactToastify.css"; //add this line

import { ToastContainer } from "react-toastify";

interface ToastProviderProps { children: React.ReactNode; }

export default function ToastProvider({ children }: ToastProviderProps) { return ( <> {children}

</>

); }

MarcinSkic commented 9 months ago

Simplest solution is to not even use {children}, just create client side wrapper and put it in root wherever you need (layout for example). CSS import is very important, without it nothing happens

"use client";

import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

export default function ToastContainerWrapper() {
    return (
        <ToastContainer position={toast.POSITION.BOTTOM_CENTER} theme="dark" />
    );
}

Example usage:

export default function Layout({ children }: React.PropsWithChildren) {

    return (
        <div className={styles["component-default-layout"]}>
            <aside>
                <a href="/">Home</a>
                <a href="/all">Everything list</a>
                <a href="/movie/all">Movies table</a>
                <a href="/person/all">People table</a>
            </aside>
            <main className="content">{children}</main>
            <ToastContainerWrapper />
        </div>
    );
}
Ngash01 commented 8 months ago

@nokwin your I did exactly how you implemented it and it worked!

IvanAdmaers commented 3 months ago

Simplest solution is to not even use {children}, just create client side wrapper and put it in root wherever you need (layout for example). CSS import is very important, without it nothing happens

"use client";

import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

export default function ToastContainerWrapper() {
    return (
        <ToastContainer position={toast.POSITION.BOTTOM_CENTER} theme="dark" />
    );
}

Example usage:

export default function Layout({ children }: React.PropsWithChildren) {

    return (
        <div className={styles["component-default-layout"]}>
            <aside>
                <a href="/">Home</a>
                <a href="/all">Everything list</a>
                <a href="/movie/all">Movies table</a>
                <a href="/person/all">People table</a>
            </aside>
            <main className="content">{children}</main>
            <ToastContainerWrapper />
        </div>
    );
}

I believe this is the best solution. Provider from @nokwin looks kinda redundant like for me

rusty120 commented 1 month ago

@nokwin Won't including 'use client' in the ToastProvider prevent server-side rending for most of your app? This seems like a big disadvantage, unless I'm missing something?

@MarcinSkic solution isolates the client rendering to just the toast wrapper, which would preferable for most cases.

MarcinSkic commented 1 month ago

@rusty120 no, there can be server side rendered components as children of client side components, otherwise any ContextProvider would prevent most of the app from being SSR, you can find more information here: https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#supported-pattern-passing-server-components-to-client-components-as-props and here https://github.com/vercel/next.js/discussions/43153