fkhadra / react-toastify

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

Error on next.js with project with app folder #951

Closed CarlosBalladares closed 1 year ago

CarlosBalladares commented 1 year ago

Do you want to request a feature or report a bug? This issue is a bug report

What is the current behavior? On nextjs new app folder routing that uses server components, the toast causes an error.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your CodeSandbox (https://codesandbox.io/s/new) example below:

Create a nextjs project with app directory in a page.tsx with "use client" render the toast container. There is an error thrown by nextjs.

Error: Hydration failed because the initial UI does not match what was rendered on the server.

Warning: Expected server HTML to contain a matching <div> in <div>.

See more info here: https://nextjs.org/docs/messages/react-hydration-error
Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

What is the expected behavior? Compatibility with the nextjs app folder or some option to prevent client rendering the root Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React? React 18, MS edge, Windows, Nextjs 13 with app folder

CarlosBalladares commented 1 year ago

downgrading to v8.0.0 from 9.1.2 seems to resolve the issue

CarlosBalladares commented 1 year ago

Another way to get rid of the error dynamic import

import dynamic from 'next/dynamic';

const ToastContainer = dynamic(() => import('react-toastify').then((module) => module.ToastContainer), {
  ssr: false,
});

const Page =()=><ToastContainer/>

or with the "use client" but don't import it directly rather import it in an import.

"use client";
import Toastify from "./Toastify";
const Page =()=><ToastContainer/>

//./Toastify.js

import { ToastContainer } from "react-toastify";

export default function Toastify() {
  return <ToastContainer />;
}
sheldon-welinga commented 1 year ago

With RSC becoming the common talk in React ecosystem, I think the best solution is for maintainers to add "use client" at the top of each client-side file as advised in React and Next Docs so library users don't have to do this on their end

fkhadra commented 1 year ago

Hey @CarlosBalladares it should work out of the box now with the latest release.

CarlosBalladares commented 1 year ago

Thanks for resolving this .

JunkyDeLuxe commented 1 year ago

Hello guys, can we have a more complete example in order to make it works ? I am using also nextjs app directory and I can find a way to load the ToastContainer from react-toastify

Stan-l-e-y commented 1 year ago

Unfortunately, I am still receiving this error. I'm on the latest toastify release and I've tried @CarlosBalladares's methods.

JunkyDeLuxe commented 1 year ago

Ok it's working prefectly now (on next13.4, with app directory), and latest stable release of react-toastify library First of all, create a TaoasterProvider like so:

'use client';

import { Slide, ToastContainer } from 'react-toastify';

interface ToastProviderProps {
    children: React.ReactNode;
}

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

Now, in your main layout.tsx file where you are declaring your root component:

export default async function Root({ children, params }: { children: React.ReactNode; params: { lang: string } }) {
    return (
        <html lang={params.lang}>
            <body>
                <ToastProvider>
                                          <Header />
                    <Suspense>
                        <main>{children}</main>
                    </Suspense>
                                          <Footer />
                </ToastProvider>
            </body>
        </html>
    );
}

Now, anywhere in a client component, you can use react-toaster metods like toast()

Stan-l-e-y commented 1 year ago

Ok it's working prefectly now (on next13.4, with app directory), and latest stable release of react-toastify library First of all, create a TaoasterProvider like so:

'use client';

import { Slide, ToastContainer } from 'react-toastify';

interface ToastProviderProps {
  children: React.ReactNode;
}

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

Now, in your main layout.tsx file where you are declaring your root component:

export default async function Root({ children, params }: { children: React.ReactNode; params: { lang: string } }) {
  return (
      <html lang={params.lang}>
          <body>
              <ToastProvider>
                                          <Header />
                  <Suspense>
                      <main>{children}</main>
                  </Suspense>
                                          <Footer />
              </ToastProvider>
          </body>
      </html>
  );
}

Now, anywhere in a client component, you can use react-toaster metods like toast()

This worked for me thanks. I was still getting the error with this solution, what I was doing differently was wrapping the ToastProvider outside the body tag. Once I put it in, the error went away, hope this could help someone in the future

sheldon-welinga commented 1 year ago

Ok it's working prefectly now (on next13.4, with app directory), and latest stable release of react-toastify library First of all, create a TaoasterProvider like so:

'use client';

import { Slide, ToastContainer } from 'react-toastify';

interface ToastProviderProps {
  children: React.ReactNode;
}

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

Now, in your main layout.tsx file where you are declaring your root component:

export default async function Root({ children, params }: { children: React.ReactNode; params: { lang: string } }) {
  return (
      <html lang={params.lang}>
          <body>
              <ToastProvider>
                                          <Header />
                  <Suspense>
                      <main>{children}</main>
                  </Suspense>
                                          <Footer />
              </ToastProvider>
          </body>
      </html>
  );
}

Now, anywhere in a client component, you can use react-toaster metods like toast()

You don't need to add "use client" with the latest release unless your app is tied to other client components

PPaivank commented 8 months ago

Ok it's working prefectly now (on next13.4, with app directory), and latest stable release of react-toastify library First of all, create a TaoasterProvider like so:

'use client';

import { Slide, ToastContainer } from 'react-toastify';

interface ToastProviderProps {
    children: React.ReactNode;
}

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

Now, in your main layout.tsx file where you are declaring your root component:

export default async function Root({ children, params }: { children: React.ReactNode; params: { lang: string } }) {
    return (
        <html lang={params.lang}>
            <body>
                <ToastProvider>
                                          <Header />
                    <Suspense>
                        <main>{children}</main>
                    </Suspense>
                                          <Footer />
                </ToastProvider>
            </body>
        </html>
    );
}

Now, anywhere in a client component, you can use react-toaster metods like toast()

This worked for me thanks. I was still getting the error with this solution, what I was doing differently was wrapping the ToastProvider outside the body tag. Once I put it in, the error went away, hope this could help someone in the future

putting the ToastContainer tag inside the body tag fixed it for me, thank you!!!!

claide commented 3 months ago

Hi, I am currently facing this issue where I added a ToastProvider inside the root layout same with as the suggestions above but, toast won't appear. It only appears when I add a toast container inside the page where I call the showToast function.

I am working on multiple layouts but only one root layout which is basically inside the /src/app directory.

versions "next": "14.0.1", "react-toastify": "^10.0.4",