简体   繁体   English

Firestore onSnapshot 通过 onEffect 中的 state 附加到阵列

[英]Firestore onSnapshot appending to array through state within onEffect

I'm currently creating a to-do list within React which retrieves tasks from Firestore and stores them locally within an array using state hooks: const [todoList, setTodoList] = useState([]) .我目前正在 React 中创建一个待办事项列表,它从 Firestore 检索任务并使用 state 挂钩将它们本地存储在一个数组中: const [todoList, setTodoList] = useState([]) I've run into some roadblocks while coding this mainly because Firestore's onSnapshot function doesn't seem to play properly with React.我在编码时遇到了一些障碍,主要是因为 Firestore 的onSnapshot function 似乎无法与 React 正常配合。 The snapshot code is called on load (to retrieve existing tasks) and when a new task is created.在加载(检索现有任务)和创建新任务时调用快照代码。 The snapshot code for appending changes to an array is:将更改附加到数组的快照代码是:

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
});

There are a few issues which pop-up when I try different variations of this (pushing to empty array and then concatenating the two arrays together, etc.):当我尝试不同的变体时会弹出一些问题(推入空数组,然后将两个 arrays 连接在一起等):

  • The todo list state doesn't persist on new snapshot.待办事项列表 state 不会保留在新快照上。 For example, creating a new task task2 updates the todoList to [task2] , but creating another task task3 after that makes the first task disappear and updates the array to [task3] instead of [task2, task3] .例如,创建一个新任务task2会将 todoList 更新为[task2] ,但在此之后创建另一个任务task3会使第一个任务消失并将数组更新为[task3]而不是[task2, task3]

  • onSnapshot keeps retrieving the same tasks despite them being previously retrieved. onSnapshot 会继续检索相同的任务,尽管它们之前已被检索过。 For example, on load the initial todoList is updated to [task1, task2, task3] .例如,在加载时,初始 todoList 会更新为[task1, task2, task3] When creating a new task and calling the snapshot function again, I expect the todoList to be updated to [task1, task2, task3, task4] .创建新任务并再次调用快照 function 时,我希望 todoList 更新为[task1, task2, task3, task4] However, instead I'm returned some variation of [task1, task2, task3, task1, task2, task3, task4] which compounds whenever the snapshot function is called again.但是,相反,我返回了[task1, task2, task3, task1, task2, task3, task4]的一些变体,每当再次调用快照 function 时都会复合。

This issue seems to only happen in React and not native JavaScript (the tasks are created and retrieved just fine without any duplicates).这个问题似乎只发生在 React 而不是本机 JavaScript (任务的创建和检索很好,没有任何重复)。 Some solutions I have tried is wrapping everything within a onEffect (which I believe gave me the first problem if I didn't pass todoList as a dependency, and if I did would infinitely loop) and calling the snapshot function via unsubscribe() (which still gave me the second problem).我尝试过的一些解决方案是将所有内容包装在 onEffect 中(如果我没有将todoList作为依赖项传递,我相信这给了我第一个问题,如果我这样做了会无限循环)并通过unsubscribe()调用快照 function (其中仍然给了我第二个问题)。

Solved.解决了。 I nested everything within a useEffect with no dependencies and managed to resolve the first bullet-point regarding states not updating properly.我将所有内容都嵌套在一个没有依赖关系的 useEffect 中,并设法解决了关于状态未正确更新的第一个要点。 Instead of setting state normally using setTodoList(todoList.concat(newTasks)) , I functionally set the state using setTodoList(currentList => currentList.concat(newTasks)) (something about setState being asynchronous about useState, async isn't my specicalty).我没有使用setTodoList(todoList.concat(newTasks))通常设置 state ,而是使用setTodoList(currentList => currentList.concat(newTasks))功能设置 state . Find the answer here: https://stackoverflow.com/a/56655187/9477642 .在这里找到答案: https://stackoverflow.com/a/56655187/9477642

Here's the final snapshot update code (I somehow also resolved onSnapshot returning the entire collection instead of just changes each time but I forgot how, I'll update this if I remember why):这是最终的快照更新代码(我也以某种方式解决了 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();
}, []);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM