import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
// import ToastProvider from "./(components)/Toastify";
import { Toaster } from "react-hot-toast";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
{children}
<Toaster />
</body>
</html>
);
}
"use client";
import { getDebugger } from "@/app/lib/debugger";
import { registerNewUser } from "@/app/lib/actions";
import FormInput from "../../(components)/forms/FormInput";
import SubmitBtn from "../../(components)/forms/SubmitBtn";
// import { toast } from "react-toastify";
import toast from "react-hot-toast";
import { useFormState } from "react-dom";
const debug = getDebugger("sign-up-form");
const initialState = {
message: null,
};
const Page = () => {
const [state, formAction] = useFormState(registerNewUser, initialState);
return (
<main>
<form action={formAction}>
<FormInput
name="firstName"
label="First Name:"
type="text"
placeholder="Your First Name"
/>
<FormInput
name="lastName"
label="Last Name:"
type="text"
placeholder="Your Last Name"
/>
<FormInput
name="password"
label="Password:"
type="password"
placeholder="******"
/>
<FormInput
name="confirmPassword"
label="Confirm Password:"
type="password"
placeholder="******"
/>
<FormInput
name="email"
label="Email:"
type="email"
placeholder="Your Email Here"
/>
<SubmitBtn text="Sign Up" />
{state?.message && toast.error(state.message)}
</form>
</main>
);
};
export default Page;
"use server";
import { customFetch } from "./customFetch";
import { getDebugger } from "./debugger";
const debug = getDebugger("actions");
export const registerNewUser = async (prevState: any, formData: FormData) => {
const user = {
firstName: formData.get("firstName") as string,
lastName: formData.get("lastName") as string,
password: formData.get("password") as string,
confirmPassword: formData.get("confirmPassword") as string,
email: formData.get("email") as string,
};
try {
const { data } = await customFetch.post("/api/auth/sign-up", user);
return data;
} catch (error: any) {
return { message: error.response.data.error };
}
};
Watch the image aswell please, the number next to the button and the X times that the toast is displaying
Im trying to implement toastify inside my nextJS app, but for some reason Im getting more then 1 display of the toast, for example i got two times toastify sometimes, sometimes one, sometimes three, and so on..
but one annoying issue that im stuck on for 5 hours! is that im seeing a number next to my button, you can see that in the image, and every time I click the sign up, the number increase with 1-2-3 (depeneds on the number of the toast displaying)
Please help me solve that, if you need the github repo : https://github.com/Parselinho/handy
Thanks in advance
That's because {state?.message && toast.error(state.message)}
You must not put any execuatable code withen JSX. JSX is recreated every time the component re-renders.
You have two issues in the code:
&&
When using logical and &&
in JSX, It'll check the left side if it is true, it will print the right side. toast.error(...)
returns the id
of the toast (number) so it's printed in the dom as you can see. It's increased because every time the component re-renders it creates new toast with new id.
You must never call any function other than components withen JSX.
To achieve what you are looking for, you can use useEffect
useEffect(() => {
if (state.message) toast.error(state.message)
}, [state.message])