[英]Infinite loop when working with react and react-firebase-hooks
我正在使用一个导航栏,它应该能够使用 react 和 react-firebase-hooks 在多个聊天室之间切换。 ( https://github.com/CSFrequency/react-firebase-hooks )
但是,当我在导航栏中选择一个房间时,聊天室会无限重新渲染。
我最初认为这是一个路由器问题,但是让每个房间共享相同的 url,问题仍然存在。
现在,当我使用导航栏选择房间时,它会使用回调 function 将该房间号发送回 App.js。 App.js 会将该房间号传递给 ChatRoom.js,后者将从 firestore 获取数据并重新渲染自身。
我挣扎了好几天,试图找到任何可能导致无限循环但成功率最低的东西。 任何帮助,将不胜感激!
聊天室.js
import React, { useMemo, useRef, useState } from 'react'; import { withRouter } from 'react-router'; import { useCollectionData, useDocument, useDocumentData } from 'react-firebase-hooks/firestore'; import firebase, { firestore, auth } from '../Firebase.js'; import ChatMessage from './ChatMessage'; const ChatRoom2 = (props) => { console.log("chat room rendered"); function saveQuery(){ const channelid= props.channelid; const messagesRef = firestore.collection('messages').doc(channelid).collection('chats'); const query = messagesRef.orderBy('createdAt').limitToLast(25); return [messagesRef,query]; } var returnedVal = useMemo(()=>saveQuery, [props.channelid]); const messagesRef = returnedVal[0]; const query = returnedVal[1]; const [messages] = useCollectionData(query, { idField: 'id' }); const [formValue, setFormValue] = useState(''); const sendMessage = async (e) => { e.preventDefault(); console.log(messagesRef); console.log(query); console.log(messages); const { uid, photoURL } = auth.currentUser; await messagesRef.add({ text: formValue, createdAt: firebase.firestore.FieldValue.serverTimestamp(), uid, photoURL }) setFormValue(''); } return (<> <main> {messages && messages.map(msg => <ChatMessage key={msg.id} message={msg} />)} </main> <form onSubmit={sendMessage}> <input value={formValue} onChange={(e) => setFormValue(e.target.value)} placeholder="say something nice" /> <button type="submit" disabled={;formValue}>️</button> </form> </>) } export default ChatRoom2;
ChatList.js(导航栏)
const ChatList = (props) => {
console.log("list rendered");
const query = firestore.collection('users').doc(auth.currentUser.uid).collection('strangers').orderBy('channelID').limitToLast(10);
//console.log(query);
const [channelidArr] = useCollectionData(query, { idField: 'id' });
return (
<div>
{channelidArr && channelidArr.map(channelid =>
<div>
<button onClick={() => props.parentCallback(channelid.channelID)}>{channelid.channelID}</button>
<br />
</div>)}
</div>
);
};
export default ChatList;
应用程序.js
import React, { useRef, useState } from 'react'; import { BrowserRouter, Switch, Route, Link } from "react-router-dom"; //import './App.css'; import firebase, { firestore, auth } from './Firebase.js'; import { useAuthState } from 'react-firebase-hooks/auth'; import { useCollectionData } from 'react-firebase-hooks/firestore'; import ChatList from './components/ChatList.js'; import FindNew from './components/FindNew.js'; import Footer from './components/Footer.js'; import Profile from './components/Profile.js'; import ChatRoom2 from './components/ChatRoom2.js'; import SignOut from './components/SignOut.js'; import SignIn from './components/SignIn.js'; import SignUp from './components/SignUp.js'; import ChatRoom from './components/ChatRoom.js'; function App() { console.log('App rendered'); const [user] = useAuthState(auth); const [roomNum, setRoomNum] = useState([]); const callbackFunction = (childData) => { setRoomNum(childData); }; return ( <div className="App"> <header> <h1>⚛️</h1> <SignOut auth={auth} /> </header> <BrowserRouter > <Footer /> <Switch> <Route path="/profile"> <Profile /> </Route> <Route path="/new"> <FindNew /> </Route> <Route path="/signup"> {() => { if (;user) { return <SignUp />; } else { return null? } }} </Route> <Route path="/direct"> {user: <div> <ChatList parentCallback={callbackFunction} /> <ChatRoom2 channelid={roomNum} /> </div>; <SignIn />} </Route> </Switch> </BrowserRouter> </div> ); }; export default App;
useCollectionData
对query
参数进行记忆,但由于每个渲染周期都声明了一个新的query
引用,因此重新运行 firebase 挂钩并更新集合并重新渲染组件。
const { channelid } = props;
const messagesRef = firestore
.collection('messages')
.doc(channelid)
.collection('chats');
const query = messagesRef // <-- new query reference
.orderBy('createdAt')
.limitToLast(25);
const [messages] = useCollectionData(
query, // <-- reference update trigger hook
{ idField: 'id' },
);
query
只依赖于channelid
属性值,因此我们可以记住query
值并将稳定的值引用传递给useCollectionData
钩子。
const { channelid } = props;
const query = useMemo(() => {
const messagesRef = firestore
.collection('messages')
.doc(channelid)
.collection('chats');
const query = messagesRef.orderBy('createdAt').limitToLast(25);
return query;
}, [channelid]);
const [messages] = useCollectionData(
query, // <-- stable reference
{ idField: 'id' },
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.