我正在用Next.js, Node.js和Express.js构建一个记忆游戏应用程序。我的登录页面有问题。
先提交表单没有问题。但是在第一次提交表单之后,Login组件会重新呈现不止一次。
随着表单提交次数的增加,重新呈现的次数随着cumulative
的增加而增加。为什么会发生这种情况?
当我点击提交按钮时,组件需要渲染一次,但是组件重新渲染了很多次。
代码:
"use client";
import React from "react";
import { z } from "zod";
import styles from "./index.module.scss";
import "./index.module.scss";
import Link from "next/link";
import { useGetUserMutation } from "@/src/app/store/features/api/apiSlice";
function Login() {
console.log("resfles");
const [isErrExist, setIsErrExist] = React.useState({
status: false,
emailText: "",
passwordText: "",
});
const [getUser, { isLoading, data }] = useGetUserMutation();
const userSchema = z.object({
email: z.string().email(),
password: z
.string()
.min(6, { message: "Your Password must have to minumum 5 character" })
.max(10, { message: "Your Password must maximum 10 characters" }),
});
if (typeof window !== "undefined") {
document.getElementById("form_")?.addEventListener("submit", (e) => {
e.preventDefault();
const spanOne = document.getElementById("spnOne") as HTMLElement;
const spanTwo = document.getElementById("spnTwo") as HTMLElement;
spanOne.innerHTML = "";
spanTwo.innerHTML = "";
const _form = document.getElementById("form_") as HTMLFormElement;
const formData = new FormData(_form);
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (typeof email !== undefined && typeof password !== undefined) {
const data_ = Object.create(null);
Object.defineProperties(data_, {
email: {
value: email,
writable: true,
},
password: {
value: password,
writable: true,
},
});
const result = userSchema.safeParse(data_);
if (result.success) {
console.log(data_);
getUser({
email: data_.email,
password: data_.password,
})
.unwrap()
.then((res) => console.log(res))
.catch((err) => console.log(err));
spanOne.innerHTML = "";
spanTwo.innerHTML = "";
} else {
setIsErrExist({ ...isErrExist, status: true });
const errArr = result.error.issues;
const errMail = errArr.find((item) => item.path[0] == "email");
const errPas = errArr.find((item) => item.path[0] == "password");
if (errMail !== undefined) {
spanOne.innerHTML = errMail.message;
}
if (errPas !== undefined) {
spanTwo.innerHTML = errPas.message;
}
}
}
});
}
return (
<form id="form_" className={styles.form_}>
<h2>Login</h2>
<label htmlFor="email_">E-mail Adress:</label>
<input type="text" name="email" id="email_" />
<span
id="spnOne"
className={isErrExist.status ? styles.err : styles.errNone}
>
Deneme
</span>
<label htmlFor="password_">Password:</label>
<input type="text" name="password" id="password_" />
<span
id="spnTwo"
className={isErrExist.status ? styles.err : styles.errNone}
>
Deneme
</span>
<button type="submit"> {isLoading ? "Loading..." : "Send"} </button>
<Link href="register">
<h4>Go To Register Page</h4>
</Link>
</form>
);
}
export default Login;
调用addEventListener
并像在纯JavaScript中那样访问DOM元素不是你应该在React/Next.js代码中做的事情。使用内置的JSX和hooks功能。
你得到的行为是由于每次渲染后的事实,为submit
添加了一个额外的事件处理程序,因为你没有删除它们。
您可以创建一个handleSubmit
函数,并将其提供给form
。使用useRef
而不是调用getElementById
,如下所示:
"use client";
// Previous imports ...
// New imports:
import { FormEvent, useRef } from "react";
function Login() {
// Previous code ...
// New code :
const spanOneRef = useRef<HTMLSpanElement>(null);
const spanTwoRef = useRef<HTMLSpanElement>(null);
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const spanOne = spanTwoRef.current!;
const spanTwo = spanTwoRef.current!;
spanOne.innerHTML = "";
spanTwo.innerHTML = "";
const _form = e.currentTarget;
const formData = new FormData(_form);
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (typeof email !== undefined && typeof password !== undefined) {
const data_ = Object.create(null);
Object.defineProperties(data_, {
email: {
value: email,
writable: true,
},
password: {
value: password,
writable: true,
},
});
const result = userSchema.safeParse(data_);
if (result.success) {
console.log(data_);
getUser({
email: data_.email,
password: data_.password,
})
.unwrap()
.then((res) => console.log(res))
.catch((err) => console.log(err));
spanOne.innerHTML = "";
spanTwo.innerHTML = "";
} else {
setIsErrExist({ ...isErrExist, status: true });
const errArr = result.error.issues;
const errMail = errArr.find((item) => item.path[0] == "email");
const errPas = errArr.find((item) => item.path[0] == "password");
if (errMail !== undefined) {
spanOne.innerHTML = errMail.message;
}
if (errPas !== undefined) {
spanTwo.innerHTML = errPas.message;
}
}
}
};
return (
<form id="form_" className={styles.form_} onSubmit={handleSubmit}>
<h2>Login</h2>
<label htmlFor="email_">E-mail Adress:</label>
<input type="text" name="email" id="email_" />
<span
id="spnOne"
ref={spanOneRef}
className={isErrExist.status ? styles.err : styles.errNone}
>
Deneme
</span>
<label htmlFor="password_">Password:</label>
<input type="text" name="password" id="password_" />
<span
id="spnTwo"
ref={spanTwoRef}
className={isErrExist.status ? styles.err : styles.errNone}
>
Deneme
</span>
<button type="submit"> {isLoading ? "Loading..." : "Send"} </button>
<Link href="register">
<h4>Go To Register Page</h4>
</Link>
</form>
);
}
export default Login;
我在这个bug中找到了答案。
如果你不使用严格模式,它不应该发生,如果不是很重要,你可以在next.config.js文件exp
const nextConfig = {reactStrictMode:假}
模块。export = nextConfig