React:如何通过 Firestore onSnapshot 和 useEffect 使用最新状态?

Posted

技术标签:

【中文标题】React:如何通过 Firestore onSnapshot 和 useEffect 使用最新状态?【英文标题】:React: How to use an up to date state with Firestore onSnapshot and useEffect? 【发布时间】:2020-06-05 22:03:03 【问题描述】:

我想更新我的状态,将来自 Firestore onSnapshot 的新消息添加到现有的消息数组中,但在 onSnapshot 中,我只能在订阅完成后访问状态。

const [messages, setMessages] = useState([]);

useEffect(() => 
  const ref = firestore()
    .collection('Msg_Messages')

  return ref.onSnapshot(querySnapshot =>
    setMessages(messages => messages.concat(querySnapshot.docs)))
, [])

当我收到一条消息时,我会收到:

OnMountMessages + lastMessage

而不是

OnMountMessages + allMessagesSinceMount + lastMessage

我猜是因为onSnapshot 创建了他自己的messagessetMessages 的副本。我能想到的唯一解决方案是使用 Redux 并将状态保留在组件之外,但是还有其他解决方案吗?

【问题讨论】:

关于您的猜测 - 听起来很可能。尝试将(querySnapshot => ... 更改为(function (querySnapshot) ... 谢谢,但不幸的是它产生了同样的效果 【参考方案1】:

在我看来,您对 .onSnapshot 的匿名函数是在其闭包中捕获过时版本的消息。如您所知,您可以将函数传递给 useState,但我认为编译器对冲突的名称感到困惑。试试这个:

const [messages, setMessages] = useState([]);

useEffect(() => 
  const ref = firestore()
    .collection('Msg_Messages')

  return ref.onSnapshot(querySnapshot =>
    setMessages(prevmessages => prevmessages.concat(querySnapshot.docs)))
, [])

在这种情况下,'prevmessages' 来自 useState 作为其状态的前一个值 - 并且不会与它的结果状态值 'messages' 混淆

(哦,还有:对于 QuerySnapshot,属性是“.docs”,而不是“.data”)

【讨论】:

感谢您的回复,您很好地指出了问题,但是您提供的解决方案并没有解决它。 (我编辑了 .docs 部分,为了问题的目的而简化问题是一个错误。) .onSnapshot(next()) 将与集合中的所有当前文档一起至少调用一次。如果有任何更改或添加,它将被再次调用,返回所有文档,而不仅仅是更改。你写“当我收到消息时”——这到底是怎么回事?另一个实例正在写入 Firestore?回调是否被多次调用?似乎有很多问题被遗漏了...... 问题不在于我如何处理 onSnaphot 方法,实际上第一条消息设置了所有预先存在的消息,但随后添加的每条消息都被下一条替换。是的,其他消息到达,因为另一个实例正在写入 Firestore,是的,回调被多次调用 不幸的是,问题中没有足够的内容来构建答案,而无需对“未见”部分进行疯狂推测。例如: querySnapshot.docs 属性不是文档数组 - 它是 QueryDocumentSnapshot 数组,QueryDocumentSnapshot .data() 方法返回实际文档内容。无法知道代码中的其他地方是否会出现这种情况。

以上是关于React:如何通过 Firestore onSnapshot 和 useEffect 使用最新状态?的主要内容,如果未能解决你的问题,请参考以下文章

通过 Firebase 访问 Firestore 超时(React Native 应用程序)

React Native Firebase:如何显示 Firestore 中的文本?

如何使用 react-redux-firebase 从 firestore 获取子集合

React - 显示 Firestore 时间戳

如何修复 React Native 中的 Firebase/firestore 错误?

如何使用 React-Native 在 Firestore 中获取包含特定字符串的数组的文档