我正在写一个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;
1条答案
按热度按时间taor4pac1#
我想我在
useEffect
中犯了个错误是的,您还没有在
Header
组件中为useEffect()
指定依赖项数组:如果没有依赖性数组,
useEffect()
回调将在每次render/rerender之后运行。因此,在当前代码中,会发生以下情况:1.调用
useEffect()
回调,如果设置了本地存储中的user
键,则调用setUser
1.由于
setUser()
是用一个新的对象引用调用的(执行JSON.parse()
时创建了一个新对象),React将其视为一个更新并触发一个rerender,因此我们返回到上面的步骤1,导致一个无限循环。通过向
useEffect()
调用添加一个空的依赖项数组[]
,您将告诉React仅在初始挂载时调用您的函数,而不是在后续重新呈现时调用。