skip to Main Content

I am building a memory game app with Next.js, Node.js, and Express.js. I have a problem with the login page.

There is no problem first submitting the form. But after first submitting the form Login component re-renders more than once.

As the number of form submissions increases, the number of re-render increases as cumulative. Why does this happen?

When I click the submit button component needs to be rendered once, but the component re-renders so many times.

Codes:

"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;

2

Answers


  1. I’m found the answer in this bug.

    if you are not using strict mode it should not happen if it is not very important you can turn foo react strict mode in next.config.js file exp

    const nextConfig = {
    reactStrictMode: false
    }

    module.export = nextConfig

    Login or Signup to reply.
  2. Calling addEventListener and accessing DOM elements as in plain JavaScript is not what you should do in a React/Next.js code. Use the built-in JSX and hooks capabilities.

    The behavior you are getting is due to the fact after each render, an additional event handler for submit is added, as you are not removing them.

    You could create a handleSubmit function that you give to the form. And use useRef instead of calling getElementById, like so:

    "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;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search