reactjs 下一个警告:超过最大更新深度

4nkexdtk  于 2022-12-29  发布在  React
关注(0)|答案(1)|浏览(126)

我正在写一个react Header组件,并添加了在下拉菜单中点击和退出的功能。每当我加载页面时,我会得到以下错误:
下一个设备js?3515:20警告:超出了最大更新深度。当组件在useEffect内调用setState,但useEffect没有依赖项数组,或者其中一个依赖项在每次呈现时更改时,可能会发生这种情况
我想我在useEffect中犯了一个错误(我运行了2个useEffects,一个在组件中,一个在另一个函数中),但是我不确定我哪里出错了。

import React from "react";
  import { useState, useEffect, useRef } from "react";
  import { FaChevronDown, FaLastfmSquare } from "react-icons/all";
  import { signOut } from "firebase/auth";
  import { useRouter } from "next/router";
  import { auth } from "../utils/auth";

  function useOutsideAlerter() {
    const [visible, setVisible] = useState(false);
    const ref = useRef(null);

    useEffect(() => {
      const handleHideDropdown = (event) => {
        if (event.key === "Escape") {
          setVisible(false);
        }
      };

      const handleClickOutside = (e) => {
        if (ref.current && !ref.current.contains(e.target)) {
          setVisible(false);
        }
      };

      document.addEventListener("keydown", handleHideDropdown, true);
      document.addEventListener("mousedown", handleClickOutside, true);

      return () => {
        document.removeEventListener("keydown", handleHideDropdown, true);
        document.removeEventListener("mousedown", handleClickOutside, true);
      };
    }, []);

    return { visible, ref, setVisible };
  }

  const Header = () => {
    const [user, setUser] = useState(null);

    const router = useRouter();
    const { ref, visible, setVisible } = useOutsideAlerter();

    useEffect(() => {
      const user = localStorage.getItem("user");
      if (user) {
        setUser(JSON.parse(user));
      }
    });

    const logUserOut = () => {
      signOut(auth)
        .then(() => {
          localStorage.removeItem("user");
          router.push("/");
        })
        .catch((error) => {
          console.error(error);
          alert("There was a problem signing out.");
        });
    };

    return (
      <div className="flex items-center justify-between p-4 border-b border-gray-300">
        <h1 className={"font-bold text-lg"}>Matrice</h1>
        <div ref={ref}>
          <button
            onClick={() => setVisible(!visible)}
            className="hover:bg-gray-100 rounded-md p-2 flex items-center justify-center text-gray-400"
          >
            {user?.displayName || "Login"} <FaChevronDown className={"ml-2"} />
          </button>
          {visible && (
            <div
              className={
                "absolute top-14 right-4 rounded-md border border-gray-300 bg-white overflow-hidden"
              }
            >
              {user && (
                <button
                  onClick={logUserOut}
                  className={
                    "text-left text-sm hover:bg-blue-700 hover:text-white w-full px-4 py-2"
                  }
                >
                  Log Out
                </button>
              )}
              <button
                onClick={() =>
                  router.replace(
                    "mailto:email"
                  )
                }
                className={
                  "text-left text-sm hover:bg-blue-700 hover:text-white w-full px-4 py-2"
                }
              >
                Request Feature
              </button>
            </div>
          )}
        </div>
      </div>
    );
  };

  export default Header;
taor4pac

taor4pac1#

我想我在useEffect中犯了个错误
是的,您还没有在Header组件中为useEffect()指定依赖项数组:

useEffect(() => {
  const user = localStorage.getItem("user");
  if (user) {
    setUser(JSON.parse(user));
  }
}, []); // <--- added empty dependency array

如果没有依赖性数组,useEffect()回调将在每次render/rerender之后运行。因此,在当前代码中,会发生以下情况:

  1. React渲染JSX
    1.调用useEffect()回调,如果设置了本地存储中的user键,则调用setUser
    1.由于setUser()是用一个新的对象引用调用的(执行JSON.parse()时创建了一个新对象),React将其视为一个更新并触发一个rerender,因此我们返回到上面的步骤1,导致一个无限循环。
    通过向useEffect()调用添加一个空的依赖项数组[],您将告诉React仅在初始挂载时调用您的函数,而不是在后续重新呈现时调用。

相关问题