next.js 为什么会出现InternalError:我的NextJS组件有太多的递归?

kupeojn6  于 2022-11-05  发布在  其他
关注(0)|答案(1)|浏览(144)

我有一个NextJS应用程序,它使用Firebase实时数据库来获取数据。但是,我得到了一个InternalError:太多的递归每次我使用页面的生产版本。我在本地开发服务器上没有得到任何错误。
代码- index.js

import { ref, getDatabase, get, child, set } from "firebase/database";
import { useState, useEffect } from "react";
import { app } from "../lib/firebase";
import Subject from "../components/Subject";
export default function Student() {
  const dbref = ref(getDatabase(app));
  const timetable = {
    Monday: ["DAA"],
    Tuesday: ["COMP", "ALC"],
    Wednesday: ["BEE", "OS"],
    Thursday: ["OE", "IT", "DM"],
    Friday: ["DBMS", "S&S"],
  };
  const days = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
  ];
  const [data, setData] = useState({});
  const [date, setDate] = useState(
    new Date().toLocaleDateString("en-GB").replaceAll("/", "-")
  );
  const [day, setDay] = useState(days[new Date().getDay()]);
  useEffect(() => {
    console.log("Data Fetched!");
    get(child(dbref, "data/"))
      .then((snapshot) => snapshot.val())
      .then((d) => {
        if (d) setData(d);
      })
      .catch((e) => console.error(e));
  }, []);
  useEffect(() => {
    console.log("Data Updated!");
    set(child(dbref, "data/"), data).catch((e) => console.error(e));
  }, [data]);
  return (
    <main className="">
      <h1 className="text-4xl">Student View : </h1>
      <p>Selected Date : {date}</p>
      <p>Day : {day}</p>
      <p>Selected Day&apos;s subjects : {timetable[day].join(", ")}</p>
      <h3>Set Date :</h3>
      <input
        type={"date"}
        id="date"
        name="date"
        onChange={(e) => {
          if (e.target.valueAsDate !== null) {
            setDate(
              e.target.valueAsDate
                .toLocaleDateString("en-GB")
                .replaceAll("/", "-")
            );
            setDay(days[e.target.valueAsDate.getDay()]);
          }
        }}
      />
      {timetable[day].map((e) => (
        <Subject key={e} name={e} data={data} setData={setData} date={date} />
      ))}
    </main>
  );
}

Subject.jsx

export default function name({ name, data, setData, date }) {
  function todayTaken() {
    setData((old) => ({
      ...old,
      [date]: { ...old[date], [name]: 1 },
    }));
  }
  function notTaken() {
    setData((old) => ({
      ...old,
      [date]: { ...old[date], [name]: 0 },
    }));
  }
  function Cancelled() {
    setData((old) => ({
      ...old,
      [date]: { ...old[date], [name]: -1 },
    }));
  }
  return (
    <div className="border-2 p-4">
      <h2>Subject : {name}</h2>
      <div className="flex flex-row gap-4">
        <button
          className="bg-blue-500 py-2.5 px-4 text-white rounded-md"
          onClick={todayTaken}
        >
          Class Taken Today
        </button>
        <button
          className="bg-red-500 py-2.5 px-4 text-white rounded-md"
          onClick={notTaken}
        >
          Not Taken Today
        </button>
        <button
          className="bg-indigo-500 py-2.5 px-4 text-white rounded-md"
          onClick={Cancelled}
        >
          Cancelled
        </button>
        <h2>
          Today&apos;s status :{" "}
          {data[date]===undefined || data[date][name] === undefined
            ? "Not set"
            : data[date][name] === 1
            ? "Class Taken"
            : data[date][name] === 0
            ? "Class Not Taken"
            : data[date][name] === -1
            ? "Class Cancelled"
            : ""}
        </h2>
      </div>
    </div>
  );
}

我不确定哪里出了问题,有人能告诉我哪里出了问题吗?第一个useEffect在组件挂载时从Firebase获取数据,然后当数据被更改时,数据被set在Firebase上,这意味着它不会触发重新渲染。我不确定这里出了什么问题。控制台没有提供任何有用的信息。

roejwanj

roejwanj1#

您正在创建一个具有以下两种效果的无限循环:

useEffect(() => {
  console.log("Data Fetched!");
  get(child(dbref, "data/"))
    .then((snapshot) => snapshot.val())
    .then((d) => {
      if (d) setData(d);
    })
    .catch((e) => console.error(e));
}, []);
useEffect(() => {
  console.log("Data Updated!");
  set(child(dbref, "data/"), data).catch((e) => console.error(e));
}, [data]);

1.第一个效果从数据库读取/data,并通过调用setData将其设置为状态。
1.第二个效果通过将data stats的值写入数据库来响应。
1.这又会再次触发第一个效果,它会再次调用setData
1.然后再次触发第二个效果。
1.这种情况无休止地重复。
若要防止无限循环,请比较任一效果中的旧值和新值,如果它们相同,则跳过进一步处理。

相关问题