【发布时间】:2020-10-08 18:04:42
【问题描述】:
我有一个要渲染的数据对象数组。这个数据数组由我在 React 钩子中声明的 Firestore onSnapshot 函数填充:useEffect。这个想法是当新数据添加到firestore时应该更新dom,并且当从firestore db修改数据时应该修改dom。 添加新数据可以正常工作,但是在修改数据时会出现问题。 下面是我的代码:
import React, {useState, useEffect} from 'react'
...
const DocList = ({firebase}) => {
const [docList, setDocList] = useState([]);
useEffect(() => {
const unSubListener = firebase.wxDocs()
.orderBy("TimeStamp", "asc")
.onSnapshot({
includeMetadataChanges: true
}, docsSnap => {
docsSnap.docChanges()
.forEach(docSnap => {
let source = docSnap.doc.metadata.fromCache ? 'local cache' : 'server';
if (docSnap.type === 'added') {
setDocList(docList => [{
source: source,
id: docSnap.doc.id,
...docSnap.doc.data()
}, ...docList]);
console.log('document added: ', docSnap.doc.data());
} // this works fine
if (docSnap.type === 'modified') {
console.log('try docList from Lists: ', docList); //this is where the problem is, this returns empty array, i don't know why
console.log('document modified: ', docSnap.doc.data()); //modified data returned
}
})
})
return () => {
unSubListener();
}
}, []);
显然,我知道我用空 deps 数组声明 useEffect 的方式是让它运行一次,如果我应该在 deps 数组中包含docList,整个效果就会开始无限运行。
请问有什么办法吗?
【问题讨论】:
-
你可以做
setDocList(current=>current.map(item=>... -
我知道这不是你想听到的,但我可能会建议使用
useReducerreactjs.org/docs/hooks-reference.html#usereducer,而不是useState来跟踪对象数组。它可以使更新更容易跟踪。至于你的错误,我不认为setDocList,即使使用 prevState 函数,在你进入 if 语句时也能保证是最新的。您是否考虑过仅添加所有文档 (type === 'added' || type === 'modified'),并在 useEffect 之外进行排序/过滤? -
看来你需要使用setLoading方法来管理来自Firebase的响应,我找到了这篇文章,希望对medium.com/javascript-in-plain-english/…有帮助
-
@HMR 谢谢,但是当我尝试这个时, current 的值是空数组,所以没有什么可以映射。
-
@BrettEast 我会试试这个,希望它能解决问题
标签: reactjs firebase google-cloud-firestore use-effect use-state