从数据库获取数据时使用useEffect无限循环

问题描述

在我的项目中,用于发送获取我的用户数据并显示它们的请求。我写了上面的代码,但是我意识到,如果我将“ people”传递给useEffect的依赖项(第二个参数),react将无限请求发送到我的Firebase,但是如果我删除并保持第二个参数为空,useEffect可以正确解决这些区别两个?

这是进入无限循环的代码

const [people,setPeople]=useState([])

useEffect(() => {
    const unsubscribe=database.collection("people").onSnapshot(snapshot=>
        setPeople(snapshot.docs.map(doc=>doc.data()))
        )
        

    return () => {
        unsubscribe()
    }
},[people]) // if i change the second parameter with an empty list this problem solved.

return (
    <div>
        <h1>TinderCards</h1>
        <div className="tinderCards_cardContainer">
        {people.map(person =>
           <TinderCard
            className="swipe"
            key={person.name}
            preventSwipe={["up","down"]}
           >
            <div style={{backgroundImage: `url(${person.url})`}} className="card">
                <h3>{person.name}</h3>

            </div>
            </TinderCard> 
            )}
        </div>

    </div>
)

解决方法

问题是在useEffect中设置状态后,people值将被更改,这将触发另一个useEffect调用,从而导致无限循环。

您可以对此进行修改:-

useEffect(() => {
    const unsubscribe=database.collection("people").onSnapshot(snapshot=>
        setPeople(snapshot.docs.map(doc=>doc.data()))
        )
        

    return () => {
        unsubscribe()
    }
},[])

,

实质上,每次依赖项数组(第二个参数)中的任何依赖项发生变化时,useEffect钩子都会运行内部函数代码。

由于setPeople会改变人们,因此效果会无限循环地运行:

useEffect(() => {
  ... setPeople() ... // <- people changed
},[people]);         // <- run every time people changes

如果您需要某种方式的人的价值,并且需要将其放在依赖项数组中,则检查的一种方法是是否未定义people

useEffect(() => {
  if (!people) {
    // ... do something
    setPeople(something);
  }
},[people]);

正如您正确指出的那样,当组件被“挂载”时,简单地去除people依赖关系就可以使效果只运行一次。

另外,您可能想知道为什么people会发生变化,如果要获取相同的准确结果。这是因为比较比较浅,并且每次创建数组时,它都是一个不同的对象:

const a = [1,2,3];
const b = [1,3];

console.log(a === b); // <- false

您需要为此进行深度相等性检查。

,

问题

useEffect每当分配给依赖项数组的任何值更改时都运行。既然如此,您将在people调用之后更新db。对数组people的引用发生了变化,因此在useEffect上触发了无限循环

解决方案

您不需要将人员放入依赖项数组中。 您的useEffect函数不依赖于people

useEffect(() => {
    const unsubscribe=database.collection("people").onSnapshot(snapshot=>
        setPeople(snapshot.docs.map(doc=>doc.data()))
        )
        

    return () => {
        unsubscribe()
    }
},[])
,

主要问题是在每次设置调用中创建的人员数组都不相同。对象是完全不同的。 我也遇到了麻烦,因为我想在管理面板中将一些新的“人员”添加到数据库后立即显示内容,但是事实证明,如果不刷新此内容就无法解决,否则您可以自己创建钩子进行适当的比较。

也许您可以通过比较PEOPLE数组的长度来尝试。我还没有尝试过,但是我认为它可以工作。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...