【发布时间】:2021-04-28 06:14:33
【问题描述】:
我正在使用一个导航栏,它应该能够使用 react 和 react-firebase-hooks 在多个聊天室之间切换。 (https://github.com/CSFrequency/react-firebase-hooks)
但是,当我在导航栏中选择一个房间时,聊天室会无限重新渲染。
我最初认为这是一个路由器问题,但让每个房间共享相同的 url,问题仍然存在。
现在,当我使用导航栏选择房间时,它会使用回调函数将该房间号发送回 App.js。 App.js 会将该房间号传递给 ChatRoom.js,后者将从 firestore 获取数据并重新渲染自身。
我挣扎了好几天,试图找到任何可能导致无限循环的东西,但收效甚微。任何帮助将不胜感激!
ChatRoom.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;
App.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;
【问题讨论】:
-
你能分辨出哪个组件在渲染循环吗?您是否尝试过进一步简化代码以隔离哪个组件/钩子的使用触发了渲染循环?
-
您好,感谢您的回复。聊天室组件导致无限循环,事件发生的顺序是:应用渲染->聊天列表渲染->聊天室渲染->聊天列表渲染->聊天室无限渲染。在 chunk.js 文件中,它说“ const { channelid } = props.channelid; ”导致错误。我是 react 新手,如果我说的某些事情没有任何意义,我很抱歉。
-
用这段代码创建一个运行的代码框可能很困难(你可以试试)。很少的想法。 (1) 如果你在聊天室组件中使用了
useCollectionDataOnce钩子怎么办? (2) 如果您在聊天室中注释掉const [messages] = useCollectionData(query, { idField: 'id' });,它是否仍然呈现循环?能否包含一个更完整的app.js组件,以便我们查看回调和roomNum值是如何维护的。 -
您好,感谢您再次回复!我试过你的建议。1)在聊天室中使用 useCollectionDataOnce 钩子也会导致无限循环。 2) 删除 useCollectionData 不会导致无限循环。 3) 我更新了 App.js,它现在包含回调函数和 roomNum 状态。
-
谢谢。好的,我怀疑这可能是由于
query在每个渲染周期都被重新声明并且query最终成为useCollectionData挂钩依赖项(我已经挖掘了源代码并且我认为就是这种情况)。尝试使用useMemo挂钩来记忆query值并依赖于channelid属性,因此query是useCollectionData挂钩的稳定参考值。
标签: javascript reactjs firebase google-cloud-firestore react-hooks