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 };
}
};
введите сюда описание изображения
Посмотрите также на изображение, число рядом с кнопкой и X раз, когда отображается тост.
Я пытаюсь реализовать toastify в своем приложении nextJS, но по какой-то причине я получаю более одного отображения всплывающего уведомления, например, иногда я получал тостирование два раза, иногда один, иногда три и так далее.
но есть одна неприятная проблема, над которой я застрял на 5 часов! Я вижу номер рядом с моей кнопкой, вы можете видеть это на изображении, и каждый раз, когда я нажимаю на регистрацию, число увеличивается на 1-2-3 (зависит от количества отображаемых тостов)
Пожалуйста, помогите мне решить эту проблему, если вам нужен репозиторий GitHub: https://github.com/Parselinho/handy
заранее спасибо





Это потому что {state?.message && toast.error(state.message)}
Вы не должны помещать какой-либо исполняемый код в JSX. JSX воссоздается каждый раз при повторной визуализации компонента.
У вас есть две проблемы в коде:
&&При использовании логического и && в JSX он проверит левую часть, если она истинна, и напечатает правую часть. toast.error(...) возвращает id тоста (число), поэтому оно напечатано в dom, как вы можете видеть. Оно увеличено, потому что каждый раз, когда компонент выполняет повторную визуализацию, он создает новое всплывающее уведомление с новым идентификатором.
Вы никогда не должны вызывать в JSX какую-либо функцию, кроме компонентов.
Чтобы достичь того, чего вы ищете, вы можете использовать useEffect
useEffect(() => {
if (state.message) toast.error(state.message)
}, [state.message])