如何使用Firebase和useEffect()正确更新状态?

我正在尝试从Firebase提取数据,然后将其推送到我的状态。目标是创建一种机制,该机制将在Firebase中的每次数据更改时执行该操作。

我与on()一起使用了useEffect()方法。不幸的是,即使状态改变,React也不会重新渲染我的组件。 (忽略直接参考,仅用于测试)

const [tasks,setTasks] = useState([]);

    useEffect(() => {
        const fetchedTasks = [];
        const ref = props.firebase.db.ref('users/1zfRCHmD4MVjJj7L884LL4TMwAH3');
        const listener = ref.on('value',snapshot => {
            snapshot.forEach(childsnapshot => {
                const key = childsnapshot.key;
                const data = childsnapshot.val();
                fetchedTasks.push({ id: key,...data });
            });
            setTasks(fetchedTasks);
        });
        return () => ref.off('value',listener);
    },[]);

这时,当我在Firebase控制台中手动更改数据时,我可以在开发工具中看到它触发了侦听器,数据已获取,但已与以前的状态(任务)合并。

我希望它取代以前的状态。其次,该组件未重新渲染。我知道空的依赖项列表对此负责(“ []”),并且组件仅安装一次,但是当我删除列表时,该组件正在更新并迅速冻结我的浏览器。我也尝试过"[tasks]",结果很相似-组件一次又一次地重新渲染。 Firebase由上下文提供,ESLint显示以下内容:

  

“ React Hook useEffect缺少依赖项:'props.firebase.db'。要么包含它,要么删除依赖项数组。”

当我这样做时,它仍然无法正常工作,并且组件没有更新。

tttaaannnzzzhhhiii 回答:如何使用Firebase和useEffect()正确更新状态?

我的评论解决了这个问题,这是官方的答案:

状态总是被合并的原因是,变量fetchedTasks仅在钩子useEffect运行onMount时才声明一次。之后,每次您的Firebase数据库更新新值并调用fetchedTasks.push(...)时,您都将压入相同的“旧”数组。因此,您的列表越来越长。

一种解决方案是只重新声明fetchedTasks,或将其设置为空档。

const [tasks,setTasks] = useState([]);

    useEffect(() => {
        const ref = props.firebase.db.ref('users/1zfRCHmD4MVjJj7L884LL4TMwAH3');
        const listener = ref.on('value',snapshot => {
            const fetchedTasks = [];
            snapshot.forEach(childSnapshot => {
                const key = childSnapshot.key;
                const data = childSnapshot.val();
                fetchedTasks.push({ id: key,...data });
            });
            setTasks(fetchedTasks);
        });
        return () => ref.off('value',listener);
    },[props.firebase.db]);

另一种方法是改为使用.map,并使用setTasks的返回值。我认为这将是我的首选:

const [tasks,snapshot => {
            const fetchedTasks = snapshot.map(childSnapshot => {
                const key = childSnapshot.key;
                const data = childSnapshot.val();
                return { id: key,...data };
            });
            setTasks(fetchedTasks);
        });
        return () => ref.off('value',[props.firebase.db]);

另外请注意,您必须将props.firebase.db传递给依赖项数组,才能摆脱eslint警告。对props.firebase.db的引用永远不应更改,因此应保存以在依赖项数组中声明。

本文链接:https://www.f2er.com/3160744.html

大家都在问