【问题标题】:Error: React Hook "useDocumentOnce" is called conditionally. React Hooks must be called in the exact same order in every component render错误:有条件地调用 React Hook “useDocumentOnce”。在每个组件渲染中,必须以完全相同的顺序调用 React Hooks
【发布时间】:2022-02-11 22:35:31
【问题描述】:

我正在使用 NextJS、TailwindCSS、Firebase 制作应用程序,它在本地主机上 100% 正常工作,但在 在 Vercel 上部署时,我收到以下 错误

15:18 错误:有条件地调用 React Hook “useRouter”。在每个组件渲染中,必须以完全相同的顺序调用 React Hooks。反应钩子/钩子规则 17:39 错误:有条件地调用 React Hook “useDocumentOnce”。在每个组件渲染中,必须以完全相同的顺序调用 React Hooks。反应钩子/钩子规则

我无法理解为什么在将我的应用程序部署到 Vercel 时出现此错误。可能与 google API 控制台中的重定向链接有关

这是我的[id].js 文件:

import TextEditor from "../../components/TextEditor";
import Button from "@material-tailwind/react/Button";
import Icon from "@material-tailwind/react/Icon";
import { useRouter } from "next/dist/client/router";
import { db } from "../../firebase";
import { useDocumentOnce } from "react-firebase-hooks/firestore";
import { getSession, signOut, useSession } from "next-auth/client";
import Login from "../../components/Login";

function Doc() {
  const [session, loading] = useSession();
  console.log(session);
  if (!session) return <Login />;

  const router = useRouter();
  const { id } = router.query;
  const [snapshot, loadingSnapshot] = useDocumentOnce(
    db.collection("userDocs").doc(session.user.email).collection("docs").doc(id)
  );

  // Redirect if user tries to access a URL they do not have access to...
  if (!loadingSnapshot && !snapshot?.data()?.fileName) {
    // Filename will not be present if the user doesnt have access...
    router.replace("/");
  }

  return (
    <div>
      <header className="flex justify-between items-center p-3 pb-1">
        <span onClick={() => router.push("/")} className="cursor-pointer">
          <Icon name="description" size="5xl" color="blue" />
        </span>
        <div className="flex-grow px-2">
          <h2 className="text-lg text-left">{snapshot?.data()?.fileName}</h2>
          <div className="flex items-center text-sm -ml-1 h-8 text-gray-600 space-x-1">
            <p className="option">File</p>
            <p className="option">Edit</p>
            <p className="option">View</p>
            <p className="option">Insert</p>
            <p className="option">Format</p>
            <p className="option">Tools</p>
          </div>
        </div>

        <Button
          color="lightBlue"
          buttonType="filled"
          size="regular"
          className="hidden md:!inline-flex h-10"
          rounded={false}
          block={false}
          iconOnly={false}
          ripple="light"
        >
          <Icon name="people" size="md" /> SHARE
        </Button>

        <img
          onClick={signOut}
          className="cursor-pointer h-10 w-10 rounded-full ml-2"
          src={session.user.image}
          alt=""
        />
      </header>
      <TextEditor />
    </div>
  );
}

export default Doc;

export async function getServerSideProps(context) {
  const session = await getSession(context);

  return {
    props: {
      session,
    },
  };
}

【问题讨论】:

  • 如果未定义session,请尝试将null 传递给useDocumentOnce()。然后你可以把所有的钩子调用都移到if (!session) return &lt;Login /&gt;;上面。

标签: reactjs firebase react-hooks next.js vercel


【解决方案1】:

您可以提前返回,然后再在线拨打useDocumentOnce

if (!session) return <Login />

这并不像错误所说的那样好。你应该确保每次渲染时总是渲染相同数量的钩子。在您的情况下,您正在调用 3 个钩子。但是如果没有定义会话,你只渲染 1 个钩子。这就是你必须解决的问题。

【讨论】:

  • 在更改return &lt;Login /&gt; 的位置时,我得到错误会话未定义
  • TypeError: Cannot read properties of null (reading 'user')
  • 请检查更新的答案
  • 我明白你想说的话。我的钩子数量取决于条件,但我实际上被困在这里。 useDocumentOnce 需要会话,这是另一个钩子。所以为了让会话首先加载,你可以看到我最后做了什么const session = await getSession(context);。如果您建议我应该对代码进行任何更改以使代码正常工作,那对我来说会很神奇
猜你喜欢
  • 1970-01-01
  • 2020-11-27
  • 2022-12-09
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 2021-03-20
  • 1970-01-01
  • 2019-12-28
相关资源
最近更新 更多