繁体   English   中英

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

[英]How to properly update state with Firebase and useEffect()?

我正在尝试从 Firebase 获取数据,然后将其推送到我的 state 中。 目标是创建一种机制,每次 Firebase 中的数据发生更改时都会执行此操作。

我使用on()方法和useEffect() 不幸的是,即使 state 发生变化,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 控制台中手动更改我的数据时,我可以在我的开发工具中看到它触发了侦听器,数据被获取,但它与之前的 state(任务)合并。

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

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

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

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

您的 state 始终合并的原因是您的变量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, setTasks] = useState([]);

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

请注意,您必须将props.firebase.db传递给您的依赖项数组,以消除 eslint 警告。 props.firebase.db的引用应该永远不会改变,所以应该保存在依赖数组中声明它。

暂无
暂无

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

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