【问题标题】:React limits the number of renders to prevent an infinite loopReact 限制渲染次数以防止无限循环
【发布时间】:2021-01-07 14:57:41
【问题描述】:

我正在制作一个应用程序,但我遇到了一个我不太理解的错误。显然,它是我用来制作受保护页面的钩子。我在下面分享错误和代码。

未处理的运行时错误错误:重新渲染次数过多。 React 限制了 防止无限循环的渲染次数。

import firebase from "firebase";

const firebaseConfig = {
  apiKey: "Key",
  authDomain: "Domain",
  databaseURL: "URL",
  projectId: "Id",
  storageBucket: "Bucket",
  messagingSenderId: "SenderId",
  appId: "appId",
  measurementId: "measurementId",
};
// Initialize Firebase
!firebase.apps.length && firebase.initializeApp(firebaseConfig);

export const database = firebase.database().ref();

const mapUserFromFirebaseAuthToUser = (user) => {
  const { displayName, email, uid } = user;
  return {
    userName: displayName,
    email,
    uid,
  };
};

export const onAuthStateChanged = (onChange) => {
  const emailProvider = new firebase.auth();
  return emailProvider.onAuthStateChanged((user) => {
    const normalizedUser = user ? mapUserFromFirebaseAuthToUser(user) : null;
    onChange(normalizedUser);
  });
};

export const loginUser = ({ email, password }) => {
  const emailProvider = new firebase.auth();
  return emailProvider.signInWithEmailAndPassword(email, password);
};

export const singUp = () => {
  const emailProvider = new firebase.auth();
  return emailProvider.signOut();
};

应用中断的页面

import { useState, useEffect } from "react";
import styles from "styles/Countries.module.css";
import useUser, { USER_STATES } from "hooks/useUser";
import NavbarMenu from "components/navBar";
import Footer from "components/footer";
import { database } from "utils/firebase";
import {
  Table,
  Button,
  Container,
  Modal,
  ModalBody,
  ModalHeader,
  ModalFooter,
  FormGroup,
} from "reactstrap";

export default function Countries() {
  const user = useUser();
  const [timeLine, setTimeLine] = useState([]);
  const [isOpenModalAdd, setIsOpenModalAdd] = useState(false);
  const [isOpenModalEdit, setIsOpenModalEdit] = useState(false);
  const [name, setName] = useState("");
  const [currency, setCurrency] = useState("");
  const [base, setBase] = useState("");
  const [km, setKm] = useState("");
  const [minute, setMinute] = useState("");
  const [code, setCode] = useState("");
  const [country, setCountry] = useState({
    name: "",
    currency_code: "",
    base_fare: "",
    per_km: "",
    per_minute: "",
  });

  useEffect(() => {
    database.child("Admin/Country").on("value", (snapshot) => {
      setTimeLine(snapshot.val());
    });
  }, []);

  const selectCountry = (data, id, status) => {
    setCountry(data);
    setCode(id);
    status === "edit" && setIsOpenModalEdit(true);
  };

  const editCountry = () => {
    database.child("Admin/Country/" + code).set(country);
    resetModalAdd();
    setIsOpenModalEdit(false);
  };

  const saveCountry = () => {
    const MapCountry = {
      name: name,
      currency_code: currency,
      base_fare: base,
      per_km: km,
      per_minute: minute,
    };
    database.child("Admin/Country/" + code).set(MapCountry);
    resetModalAdd();
    setIsOpenModalAdd(false);
  };

  const resetModalAdd = () => {
    setName("");
    setCurrency("");
    setBase("");
    setKm("");
    setMinute("");
    setCode("");
  };

  const openModalAdd = () => {
    setIsOpenModalAdd(true);
  };

  const closeModalAdd = () => {
    setIsOpenModalAdd(false);
  };

  const handleChangeName = (event) => {
    const { value } = event.target;
    setName(value);
    let string = value;
    let part = string.split("");
    if (part.length === 2) {
      let code = part[0].toUpperCase() + part[1].toUpperCase();
      setCode(code);
    }
  };

  const handleChangeData = (event) => {
    const { value } = event.target;
    setCountry(value);
  };

  const handleChangeCurrency = (event) => {
    const { value } = event.target;
    setCurrency(value);
  };

  const handleChangeBase = (event) => {
    const { value } = event.target;
    setBase(value);
  };

  const handleChangeKm = (event) => {
    const { value } = event.target;
    setKm(value);
  };

  const handleChangeMinute = (event) => {
    const { value } = event.target;
    setMinute(value);
  };

  return user ? (
    <>
      <div className={styles.container}>
        <div className={styles.principalMenu}>
          <NavbarMenu>
            <div className={styles.titleHeader}>
              <div className={styles.title}>Administration System</div>
              <div className={styles.subtitle}>User: {user.userName}</div>
            </div>
          </NavbarMenu>
        </div>
        <div>
          <h3>Country</h3>
        </div>
        <Container>
          <Button color="primary" onClick={openModalAdd}>
            New Country
          </Button>
          <Table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Currency Code</th>
                <th>Base Fare</th>
                <th>Per Km</th>
                <th>Per Minute</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
              {Object.keys(timeLine).map((i) => {
                return (
                  <tr key={i}>
                    <td>{timeLine[i].name}</td>
                    <td>{timeLine[i].currency_code}</td>
                    <td>{timeLine[i].base_fare}</td>
                    <td>{timeLine[i].per_km}</td>
                    <td>{timeLine[i].per_minute}</td>
                    <td>
                      <Button
                        color="primary"
                        onClick={selectCountry(timeLine[i], i, "edit")}
                      >
                        Editar
                      </Button>
                      {"   "}
                      <Button color="danger">Eliminar</Button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </Table>
          <Modal isOpen={isOpenModalAdd}>
            <ModalHeader>Insertar Registro</ModalHeader>
            <ModalBody>
              <div className="form-group">
                <label>Name: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  value={name}
                  onChange={handleChangeName}
                />
                <label>Currency Code: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  value={currency}
                  onChange={handleChangeCurrency}
                />
                <label>Base Fare: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  value={base}
                  onChange={handleChangeBase}
                />
                <label>Per Km: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  value={km}
                  onChange={handleChangeKm}
                />
                <label>Per Minute: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  value={minute}
                  onChange={handleChangeMinute}
                />
              </div>
            </ModalBody>
            <ModalFooter>
              <Button color="primary" onClick={saveCountry}>
                Guardar
              </Button>
              {"    "}
              <Button color="danger" onClick={closeModalAdd}>
                Cancelar
              </Button>
            </ModalFooter>
          </Modal>
          <Modal isOpen={isOpenModalEdit}>
            <ModalHeader>Editar Registro</ModalHeader>
            <ModalBody>
              <div className="form-group">
                <label>Name: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  name="name"
                  value={country.name}
                  onChange={handleChangeData}
                />
                <label>Currency Code: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  name="currency_code"
                  value={country.currency_code}
                  onChange={handleChangeData}
                />
                <label>Base Fare: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  name="base_fare"
                  value={country.base_fare}
                  onChange={handleChangeData}
                />
                <label>Per Km: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  name="per_km"
                  value={country.per_km}
                  onChange={handleChangeData}
                />
                <label>Per Minute: </label>
                <br />
                <input
                  type="text"
                  className="form-control"
                  name="per_minute"
                  value={country.per_minute}
                  onChange={handleChangeData}
                />
              </div>
            </ModalBody>
            <ModalFooter>
              <Button color="primary" onClick={editCountry}>
                Guardar
              </Button>
              {"    "}
              <Button color="danger" onClick={setIsOpenModalEdit(false)}>
                Cancelar
              </Button>
            </ModalFooter>
          </Modal>
        </Container>
        <Footer />
      </div>
    </>
  ) : user === USER_STATES.NOT_KNOWN ? (
    <>
      <div className={styles.container}>
        <h1>Loading...</h1>
      </div>
    </>
  ) : (
    <>
      <div className={styles.container}>
        <h1>Not authorized</h1>
      </div>
    </>
  );
}

用于受保护页面的钩子:

import { Router } from "next/router";
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import { onAuthStateChanged } from "utils/firebase";

export const USER_STATES = {
  NOT_LOGGED: null,
  NOT_KNOWN: undefined,
};

export default function useUser() {
  const [user, setUser] = useState(USER_STATES.NOT_KNOWN);
  const router = useRouter();

  useEffect(() => {
    onAuthStateChanged(setUser);
  }, []);

  useEffect(() => {
    user === USER_STATES.NOT_LOGGED && router.push("/login");
  }, [user]);

  return user;
}

我希望这足以帮助我。我已经尝试解决,但事实是我没有找到问题。

【问题讨论】:

  • 也许还有更多,但onClick={setIsOpenModalEdit(false)} 没有将处理程序设置为某些东西,它会调用该函数。至少你应该onClick={() =&gt; setIsOpenModalEdit(false)}

标签: reactjs next.js


【解决方案1】:

这几行的逻辑不正确:

useEffect(() => {
    onAuthStateChanged(setUser);
}, []);

useEffect(() => {
    user === USER_STATES.NOT_LOGGED && router.push("/login");
}, [user]);

我理解第一个useEffect是用来更新状态的, 但第二个 useEffect 监视此状态并返回布尔值?

应该是:而不是user === USER_STATES.NOT_LOGGED &amp;&amp; router.push("/login");

if (USER_STATES.NOT_LOGGED) { router.push("/login"); }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-25
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 2020-08-07
    相关资源
    最近更新 更多