[英]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.