我正在尝试从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'。要么包含它,要么删除依赖项数组。”
当我这样做时,它仍然无法正常工作,并且组件没有更新。
答案 0 :(得分:0)
我的评论解决了这个问题,这是官方的答案:
状态总是被合并的原因是,变量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
的引用永远不应更改,因此应保存以在依赖项数组中声明。