Javascript Firestore onSnapshot通过OneEffect中的状态附加到阵列
我目前正在React中创建一个待办事项列表,该列表从Firestore检索任务,并使用状态挂钩将它们本地存储在数组中:Javascript Firestore onSnapshot通过OneEffect中的状态附加到阵列,javascript,reactjs,firebase,google-cloud-firestore,react-hooks,Javascript,Reactjs,Firebase,Google Cloud Firestore,React Hooks,我目前正在React中创建一个待办事项列表,该列表从Firestore检索任务,并使用状态挂钩将它们本地存储在数组中:const[todoList,setTodoList]=useState([])。我在编写此代码时遇到了一些障碍,主要是因为Firestore的onSnapshot功能似乎无法正确使用React。在加载(检索现有任务)和创建新任务时调用快照代码。用于将更改附加到阵列的快照代码为: todoReference.onSnapshot(colSnapshot => { c
const[todoList,setTodoList]=useState([])
。我在编写此代码时遇到了一些障碍,主要是因为Firestore的onSnapshot
功能似乎无法正确使用React。在加载(检索现有任务)和创建新任务时调用快照代码。用于将更改附加到阵列的快照代码为:
todoReference.onSnapshot(colSnapshot => {
colSnapshot.docChanges().forEach(change => {
if (change.type === 'added') {
const taskData = change.doc.data();
todoList.push(taskData);
}
});
setTodoList(todoList); // "update state" using new array
});
当我尝试不同的版本时,会弹出一些问题(推到空数组,然后将两个数组连接在一起,等等):
- 待办事项列表状态不会在新快照上保持。例如,创建一个新任务
会将todoList更新为task2
,但创建另一个任务[task2]
之后,会使第一个任务消失,并将数组更新为task3
[task3]
- onSnapshot继续检索相同的任务,尽管之前已检索到这些任务。例如,加载时,初始todoList将更新为
。创建新任务并再次调用快照函数时,我希望todoList会更新为[task1、task2、task3]
。但是,我得到的是[task1,task2,task3,task4]
的一些变体,每当再次调用snapshot函数时,这些变体就会复合[task1,task2,task3,task1,task2,task3,task4]
这个问题似乎只发生在React中,而不是本机JavaScript中(任务的创建和检索没有任何重复)。我尝试过的一些解决方案是将所有内容包装在一个OneEffect中(我相信如果我没有将
作为依赖项传递给olist
,并且如果传递了,则会无限循环),并通过unsubscribe()
调用快照函数(这仍然给了我第二个问题) 解决了!我将所有内容嵌套在一个useEffect中,没有依赖项,并设法解决了关于状态未正确更新的第一个要点。与通常使用setTodoList(todoList.concat(newTasks))
设置状态不同,我使用setTodoList(currentList=>currentList.concat(newTasks))
从功能上设置状态(关于setState是异步的关于useState,异步不是我的专长)。在这里找到答案:
以下是最终的快照更新代码(我还以某种方式解决了onSnapshot返回整个集合的问题,而不是每次都进行更改,但我忘记了如何进行更改,如果我记得原因,我将更新此代码):
useEffect(() => {
let unsubscribe = todoReference.onSnapshot(colSnapshot => {
console.log(colSnapshot.docChanges());
let newTasks = [];
colSnapshot.docChanges().forEach(change => {
if (change.type === 'added') {
const taskData = change.doc.data();
newTasks.push(taskData);
}
});
setTodoList(currentList => currentList.concat(newTasks));
});
return () => unsubscribe();
}, []);