node.js - 如何使用useEffect正确处理firebase实时数据库监听器?
问题描述
const Messages = (props) => {
const [messages, setMessages] = useState([]);
const { currentChannel, currentUser } = props;
const messagesRef = firebase.database().ref("messages");
useEffect(() => {
if (currentChannel && currentUser) {
const channel = currentChannel.currentChannel;
let loadedMessages = [];
messagesRef.child(channel.id).on("child_added", (snap) => {
loadedMessages.push(snap.val());
});
setMessages(loadedMessages);
}
return () => messagesRef.off();
}, [currentChannel, currentUser, messagesRef]);
const displayMessages = (messages) =>
messages.length > 0 &&
messages.map((message) => (
<Message key={message.timestamp} message={message} user={currentUser} />
));
return (
<>
<MessagesHeader />
<Segment>
<Comment.Group className="messages">
{displayMessages(messages)}
</Comment.Group>
</Segment>
<MessageForm
messagesRef={messagesRef}
currentChannel={currentChannel}
currentUser={currentUser}
/>
</>
);
};
警告:已超出最大更新深度。当组件调用
setState
inside时,可能会发生这种情况useEffect
,但useEffect
要么没有依赖数组,要么每次渲染时其中一个依赖项都发生了变化。
如何防止这种无限循环?
解决方案
每次渲染时,您都在创建一个新messagesRef
对象。它可能正在处理数据库中的同一点,但它是一个新对象。更改messageRef
后,您的效果将重新运行,并且setMessages
每次都会使用全新的数组调用该效果。由于您设置了状态,因此组件会重新呈现,并且循环会重复。
大多数情况下,我建议让数据库 ref 只存在于您useEffect
的 . 但是,看起来您需要将 ref 作为道具传递给MessageForm
,所以这在这里不起作用。相反,您需要确保只创建一次数据库引用。useMemo
是一种方法:
const messagesRef = useMemo(() => {
return firebase.database().ref("messages");
}, []);
推荐阅读
- python - Script adding line break in middle of string
- shell - 如何通过 tcsh 脚本并行运行作业?
- javascript - 单击外部时隐藏列表(第 2 部分)
- jestjs - jest test 的测试输入未转换为 json 文件
- python - gtk+ vlc,MediaPlayerEndReached 事件不播放下一个视频
- ruamel.yaml - 如何使用 ruamel.yaml 将字典与基于 defaultdict 的字典打印为 yaml 文件?
- html - 表中两列之间的空间?
- c# - 如何使用 C# 为 Reading API 在 .Net Web 应用程序中读取 epub 文件?
- keycloak - 从 MDB 调用 EJB 的权限问题
- identityserver3 - IdentityServer3 idsrv.partial cookie 变得太大