使用 useEffect 无限循环

发布于 2025-01-10 08:48:35 字数 2460 浏览 1 评论 0原文

我正在创建一个在 firebase 中更新数据的项目,但是我已经控制台记录了数据并且它不断地通过。

如何从本质上停止循环以免崩溃。

import "./App.css";

import "semantic-ui-css/semantic.min.css";
import { Container, Divider, Card } from "semantic-ui-react";
import Header from "./components/Header";
import Cards from "./components/Cards/index";
import { useState, useEffect } from "react";
import { AppProvider } from "./Context/Context.js";
import "firebase/compat/auth";
import {} from "firebase/firestore";
import * as FirestoreService from "./components/service/firebase";
import firebase from "@firebase/app-compat";

function App() {
  const [user, setUser] = useState(null);
  const [cloudFucntions, setCloudFucntions] = useState();
  const [error, setError] = useState();

  useEffect(() => {
    firebase.auth().onAuthStateChanged((user) => {
      setUser(user);

      const unsubscribe = FirestoreService.getCloudFunctionItems(
        (querySnapshot) => {
          const updatedCloundFunctions = querySnapshot.docs.map((docSnapshot) =>
            docSnapshot.data()
          );
          setCloudFucntions(updatedCloundFunctions);
          console.log(updatedCloundFunctions);
        },
        (error) => setError("list-item-get-fail")
      );
      return unsubscribe;
    });
  }, [cloudFucntions]);

  return (
    <AppProvider>
      <div>
        <Container>
          <Header />

          <Divider horizontal section>
            Cloud Function Monitor
          </Divider>

          {user ? (
            <Card.Group itemsPerRow="4">
              {cloudFucntions &&
                cloudFucntions.map((cloudFunction) => {
                  return (
                    <Cards
                      key={cloudFunction.id}
                      cloudFunction={cloudFunction}
                    ></Cards>
                  );
                })}
            </Card.Group>
          ) : (
            <h2> Please sign in using the button in the top right. </h2>
          )}
        </Container>
      </div>
    </AppProvider>
  );
}

export default App;

控制台图像...

我尝试使用空数组并且不传递任何内容,但出现错误: 警告:列表中的每个子项都应该有一个唯一的“key”道具。 警告:失败的 prop 类型:提供给 CardContent 的 prop children 无效,需要 ReactNode。 警告:函数作为 React 子项无效。如果您返回一个组件而不是从渲染中返回,则可能会发生这种情况。或者也许您打算调用此函数而不是返回它。

I am creating a project that updates my data in firebase, however I have console logged the data and its constantly coming through.

How do I stop the loop essentially so that it doesn't crash.

import "./App.css";

import "semantic-ui-css/semantic.min.css";
import { Container, Divider, Card } from "semantic-ui-react";
import Header from "./components/Header";
import Cards from "./components/Cards/index";
import { useState, useEffect } from "react";
import { AppProvider } from "./Context/Context.js";
import "firebase/compat/auth";
import {} from "firebase/firestore";
import * as FirestoreService from "./components/service/firebase";
import firebase from "@firebase/app-compat";

function App() {
  const [user, setUser] = useState(null);
  const [cloudFucntions, setCloudFucntions] = useState();
  const [error, setError] = useState();

  useEffect(() => {
    firebase.auth().onAuthStateChanged((user) => {
      setUser(user);

      const unsubscribe = FirestoreService.getCloudFunctionItems(
        (querySnapshot) => {
          const updatedCloundFunctions = querySnapshot.docs.map((docSnapshot) =>
            docSnapshot.data()
          );
          setCloudFucntions(updatedCloundFunctions);
          console.log(updatedCloundFunctions);
        },
        (error) => setError("list-item-get-fail")
      );
      return unsubscribe;
    });
  }, [cloudFucntions]);

  return (
    <AppProvider>
      <div>
        <Container>
          <Header />

          <Divider horizontal section>
            Cloud Function Monitor
          </Divider>

          {user ? (
            <Card.Group itemsPerRow="4">
              {cloudFucntions &&
                cloudFucntions.map((cloudFunction) => {
                  return (
                    <Cards
                      key={cloudFunction.id}
                      cloudFunction={cloudFunction}
                    ></Cards>
                  );
                })}
            </Card.Group>
          ) : (
            <h2> Please sign in using the button in the top right. </h2>
          )}
        </Container>
      </div>
    </AppProvider>
  );
}

export default App;

Image of console...

I have tried using an empty array and not passing anything through however i get the errors:
Warning: Each child in a list should have a unique "key" prop.
Warning: Failed prop type: Invalid prop children supplied to CardContent, expected a ReactNode.
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初雪 2025-01-17 08:48:35

通常,您不能对效果最终更新的效果使用依赖项,这就是导致渲染循环的原因。对于 useEffect 挂钩,回调中根本没有引用 cloudFucntions,因此它不是依赖项。对于 Firebase 连接,更常见的是使用挂载 useEffect 挂钩,即空依赖项数组。

我还看到该组件不会取消订阅 onAuthStateChanged 检查。由于第二个云函数的获取似乎并不依赖于用户,因此您应该将它们分为自己的效果和订阅清理。

useEffect(() => {
  const unsubscribe = firebase.auth()
    .onAuthStateChanged((user) => setUser(user));
  return unsubscribe;
}, []);

useEffect(() => {
  const unsubscribe = FirestoreService.getCloudFunctionItems(
    (querySnapshot) => {
      const updatedCloundFunctions = querySnapshot
        .docs
        .map((docSnapshot) => docSnapshot.data());
      setCloudFucntions(updatedCloundFunctions);
    },
    (error) => setError("list-item-get-fail")
  );
  return unsubscribe;
}, []);

警告:列表中的每个子项都应该有一个唯一的“key”属性。

这仅意味着 key={cloudFunction.id} 不是一个足够唯一的 id,无法用作 React 键。 React 键必须在同级中是唯一的。 除非别无选择,否则不要使用数组索引作为键。不建议这样做。

如果您的云函数对象有重复的 id,或者返回重复的云函数,您应该在后端修复此问题。如果这不是您可以在后端解决的问题,那么当您在前端收到它们时,您需要生成唯一的 ID。

例子:

import { v4 as uuidV4 } from 'uuid';

...

const updatedCloundFunctions = querySnapshot
  .docs
  .map((docSnapshot) => ({
    guid: uuidV4(), // <-- generate your own GUID
    ...docSnapshot.data(),
  }));
setCloudFucntions(updatedCloundFunctions);

...

cloudFucntions.map((cloudFunction) => {
  return (
    <Cards
      key={cloudFunction.guid} // <-- use your GUID here as key
      cloudFunction={cloudFunction}
    />
  );
})}
警告:失败的 prop 类型:提供给 CardContent 的 prop 子项无效,需要 ReactNode。
警告:函数作为 React 子项无效。

对于其中的每一个,我们都需要查看我怀疑的 Cards 组件。这些警告似乎与 CartContent 组件有关。您可以添加 Cards 组件和其他相关代码,以及任何 propTypes 定义,我们可以进一步完善答案,或者您可以在 SO 上发布一个新问题,因为这些对于以下问题来说是相当课外的渲染循环和 React 键。

You can't generally use a dependency for an effect that the effect ultimately updates, this is what leads to render looping. For the useEffect hook, cloudFucntions isn't referenced at all in the callback, so it's not a dependnecy. With firebase connections it's more common to use a mounting useEffect hook, i.e. an empty dependency array.

I see also that the component doesn't unsubscribe from the onAuthStateChanged check. Since the the second cloud functions fetching doesn't appear to be dependent on the user, you should split these into their own effects and subscription clean ups.

useEffect(() => {
  const unsubscribe = firebase.auth()
    .onAuthStateChanged((user) => setUser(user));
  return unsubscribe;
}, []);

useEffect(() => {
  const unsubscribe = FirestoreService.getCloudFunctionItems(
    (querySnapshot) => {
      const updatedCloundFunctions = querySnapshot
        .docs
        .map((docSnapshot) => docSnapshot.data());
      setCloudFucntions(updatedCloundFunctions);
    },
    (error) => setError("list-item-get-fail")
  );
  return unsubscribe;
}, []);

Warning: Each child in a list should have a unique "key" prop.

This only means that key={cloudFunction.id} isn't a unique enough id to be used as a React key. React keys must be unique among siblings. Don't use the array index as key unless you've no other choice. It's not recommended.

If your cloud function objects have duplicate ids, or there are duplicate cloud functions being returned you should fix this in the backend. If this isn't something you can resolve in the backend then you'll need to generate unique ids when you receive them in the frontend.

Example:

import { v4 as uuidV4 } from 'uuid';

...

const updatedCloundFunctions = querySnapshot
  .docs
  .map((docSnapshot) => ({
    guid: uuidV4(), // <-- generate your own GUID
    ...docSnapshot.data(),
  }));
setCloudFucntions(updatedCloundFunctions);

...

cloudFucntions.map((cloudFunction) => {
  return (
    <Cards
      key={cloudFunction.guid} // <-- use your GUID here as key
      cloudFunction={cloudFunction}
    />
  );
})}
Warning: Failed prop type: Invalid prop children supplied to CardContent, expected a ReactNode.
Warning: Functions are not valid as a React child.

For each of these we'd need to see the Cards component I suspect. The warnings are with regard to a CartContent component it seems. You can add the Cards component and other relevant code, along with any propTypes definitions and we can further refine answer, or you can post a new question on SO since these are rather extra-curricular to the issue of the render looping and React keys.

一腔孤↑勇 2025-01-17 08:48:35

您对 useEffect 的依赖不正确。对 setCloudFucntions 的调用将重新触发 useEffect(因为它设置了 cloudFucntions),

  useEffect(() => {
    ...
          setCloudFucntions(updatedCloundFunctions);
    ...
  }, [cloudFucntions]);

您不需要它,您的效果不使用 cloudFucntions

警告与渲染中的键有关,看来 cloudFunction.id 可能不是唯一的。

你可以这样做

cloudFucntions.map((cloudFunction, idx) => {
  return (
    <Cards
      key={idx}
      cloudFunction={cloudFunction}
    ></Cards>
  )

You have an incorrect dependency on the useEffect. The call to setCloudFucntions will retrigger useEffect (because it sets cloudFucntions)

  useEffect(() => {
    ...
          setCloudFucntions(updatedCloundFunctions);
    ...
  }, [cloudFucntions]);

You don't need it, your effect does not use cloudFucntions.

The warning is concerning the key in the render, it seems that cloudFunction.id may not be unique.

You could do this

cloudFucntions.map((cloudFunction, idx) => {
  return (
    <Cards
      key={idx}
      cloudFunction={cloudFunction}
    ></Cards>
  )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文