[英]UseEffect infinite loop with Firebase
嗨,我正在尝试建立一个简单的聊天室,但我在阅读消息时遇到了一些问题。
const [messages, setMessages] = useState([]);
const messagesArray = [];
const messagesRef = firestore().collection('messages');
useEffect(() => {
id
? messagesRef
.where('idRequest', '==', id)
.orderBy('createdAt')
.limit(25)
.get()
.then((response) => {
response.forEach((doc) => {
messagesArray.push(doc.data());
});
setMessages(messagesArray);
console.log('Changes: ', messages);
})
: console.log('No ID provided.');
}, [messages]);
如果我使用依赖项“ messages
”运行它,它可以工作,但应用程序变得非常慢,所以我放置了一个 console.log 来检查useEffect
的流程,我认为它处于无限循环中,寻找变化和结束。 我假设发生这种情况是因为每当 useEffect 运行时,它都会“重新设置” messages
数组,从而使其再次运行。 我可以通过从依赖项数组中删除“ messages
”来解决循环问题,但问题是当发送或接收新消息时它不会再次呈现。 所以我不确定我应该做什么。
PS:聊天取决于实际用户 ID,开始的条件是确保收到 ID,否则不应查询 firestore db。
您在UseEffect
中调用SetMessages()
,它会更改messages
,从而触发您的 useEffect。
你的 linter 应该已经发现了这个。
我遇到了这个问题,以下似乎有效。 正如 @Thor0o0 所说,您需要一个条件语句来检查您是否已经在 state 中捕获了消息。
我会使用id
作为依赖而不是messages
。
const [messages, setMessages] = useState([]);
const messagesRef = firestore().collection('messages');
useEffect(() => {
if(!id) return console.log('No ID provided.');
const messagesArray = messages;
messagesRef
.where('idRequest', '==', id)
.orderBy('createdAt')
.limit(25)
.get()
.then((response) => {
response.forEach((doc) => {
const foundMsgIndex = messagesArray.findIndex(msg=>msg.id===doc.id)
if(foundMsgIndex < 0){
messagesArray.push({...doc.data(), id:doc.id});
}
});
setMessages(messagesArray);
console.log('Changes: ', messages);
})
}, [id]);
由于您说过需要将消息数组保留为 useEffect 的依赖项,因此您可以在 ref 中保留消息数组的副本,并将其与 useEffect 回调中的消息变量进行比较。
const [messages, setMessages] = useState([]);
const messagesArray = [];
const messagesRef = firestore().collection("messages");
const lastMessages = useRef();
useEffect(() => {
// Only do something if the messages variable was reassigned outside of the useEffect
if (messages !== lastMessages.current) {
id
? messagesRef
.where("idRequest", "==", id)
.orderBy("createdAt")
.limit(25)
.get()
.then((response) => {
response.forEach((doc) => {
messagesArray.push(doc.data());
});
// Update the value of the ref
lastMessages.current = messagesArray;
setMessages(messagesArray);
console.log("Changes: ", messages);
})
: console.log("No ID provided.");
}
}, [messages]);
这是有效的,因为即使组件重新渲染,ref 的值也会被保留。
检查下面的代码。
const [messages, setMessages] = useState([]);
const messagesArray = [];
const messagesRef = firestore().collection('messages');
useEffect(() => {
id
? messagesRef
.where('idRequest', '==', id)
.orderBy('createdAt')
.limit(25)
.get()
.then((response) => {
response.forEach((doc) => {
//check here if the message is already in the messages array
//before pushing it and calling setMessages. Use findIndex or
//filter method to do so.
//something like this
const messageExists = messages.findIndex(doc.data());
if (!messageExists){
messagesArray.push(doc.data());
setMessages(messagesArray);
});
})
: console.log('No ID provided.');
}, [messages]);
您在useEffect
中使用messages
的唯一一次是console.log('Changes: ', messages)
- 到那时它甚至都无效。
删除该 console.log 语句, messages
将不再是依赖项。 没有更多的循环。 id
和messageArray
是实际的依赖项,应该添加; useEffect 中都没有修改,所以没有循环。
如果您需要console.log('Changes: ', messages)
,请不要在此useEffect 中执行此操作 - 创建另一个JUST FOR THE CONSOLE.LOG 。
useEffect(() => {
console.log('Changes: ', messages);
}, [messages]);
这只会在消息更改时调用,并且不会修改消息,因此没有循环。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.