我在尝试使用 useEffect 处理 firebase 身份验证错误时收到此 "Maximum update depth exceeded."

I'm getting this "Maximum update depth exceeded." while trying to handle firebase authentication error with useEffect

我正在使用 React firebase hooks 库进行 firebase 身份验证。我正在尝试使用 useEffect 处理 signInWithEmailAndPassword 错误,但收到此无限错误。 “超过最大更新深度。当组件在 useEffect 中调用 setState 时可能会发生这种情况,但 useEffect 要么没有依赖项数组,要么依赖项之一在每次渲染时都会发生变化。”

const [signInWithEmailAndPassword, user, loading, error] =
    useSignInWithEmailAndPassword(auth);
const [info, setInfo] = useState({
    email: "",
    password: "",
  });
  const [errors, setError] = useState({
    email: "",
    password: "",
  });
  const handleLogin = async (e) => {
    e.preventDefault();
    signInWithEmailAndPassword(info.email, info.password);
  };
  useEffect(() => {
    if (error) {
      switch (error?.code) {
        case "auth/user-not-found":
          setError({
            ...errors,
            email: "No user found using that email",
          });
          setInfo({ ...info, email: "" });
          break;
        case "auth/wrong-password":
          setError({ ...errors, password: "Wrong password" });
          setInfo({ ...info, email: "" });
          break;
        default:
          toast.error("Something went wrong");
          break;
      }
    }
  }, [error, errors, info]);```

问题是 useEffect 将 re-run 每当 errorsinfo 发生变化时,取决于它:[error, errors, info]。所以当你在其中设置 setErrorssetInfo 时,你将 运行 陷入无限循环。

在这种情况下,修复非常简单 - 如果您使用 setErrors/setInfo 的函数回调版本,它将传递给您 errors/info 而无需将其作为依赖项引入:

useEffect(() => {
  if (error) {
    switch (error?.code) {
      case "auth/user-not-found":
        setErrors(errors => ({
          ...errors,
          email: "No user found using that email",
        }));
        setInfo(info => ({ ...info, email: "" }));
        break;
      case "auth/wrong-password":
        setErrors(errors => ({ ...errors, password: "Wrong password" }));
        setInfo(info => ({ ...info, email: "" }));
        break;
      default:
        toast.error("Something went wrong");
        break;
    }
  }
}, [error]);

(注意我从 setError 重命名为 setErrors 因为我发现它令人困惑,因为变量被称为 errors (复数))