如何取消firebase的useEffect订阅
Posted
技术标签:
【中文标题】如何取消firebase的useEffect订阅【英文标题】:how to cancel useEffect subscriptions of firebase 【发布时间】:2021-03-23 17:46:29 【问题描述】:我不太明白 useEffect 清理功能是如何工作的。因为无论我做什么都会收到警告:
警告:无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。
这是我的代码:
useEffect(() =>
setLoading(true)
// Get position list
const getPositionList = db.collection('lists').doc('positions').get()
.then( res =>
let data = JSON.stringify(res.data())
data = JSON.parse(data)
setPositionsList(data.list)
setLoading(false)
)
return () => getPositionList
, [])
【问题讨论】:
您在未安装的组件上更改了没有意义的状态,您会收到警告。 你能解释更多吗? 【参考方案1】:useEffect 期望取消订阅/清理函数或 null 作为返回值。您的 .get() 不是订阅,因此无需清理
但是 useEffect 不是异步的,并且 .get() 明确地返回一个需要延迟的承诺,即使使用 .then() 也是如此。你的依赖数组是空的,所以 useEffect 只被调用一次——但我怀疑你的组件在 .get() 返回之前卸载了。
您的代码需要更接近:
useEffect(() =>
setLoading(true)
(async () =>
// Get position list
await db.collection('lists').doc('positions').get()
.then( res =>
let data = JSON.stringify(res.data())
data = JSON.parse(data)
setPositionsList(data.list)
setLoading(false)
);
)();
return null
, [])
( async () => )()
创建一个匿名异步函数,然后执行它。您确实想尝试构建您的系统,以使封闭组件在加载设置为 false 之前不会卸载 - 我们在这里看不到,所以我们必须假设您这样做 that 部分是正确的。
重要的收获:
useEffect 不是异步的 .get() 是异步的( async () => )
创建匿名异步函数,( async () => )()
创建自执行匿名异步函数
【讨论】:
【参考方案2】:useEffect(() =>
setLoading(true)
// below firebase api return promise. hence no need to unsubscribe.
db.collection('lists').doc('positions').get()
.then( res =>
let data = JSON.stringify(res.data())
data = JSON.parse(data)
setPositionsList(data.list)
setLoading(false)
)
return () =>
// any clean up code, unsubscription goes here. unmounting phase
, [])
【讨论】:
【参考方案3】:根据@Dennis Vash 的回答我发现,在设置状态之前我必须检查组件是否已安装,所以我在useEffect
中添加变量,在设置状态之前我检查我添加if
语句:
useEffect(() =>
setLoading(true)
let mounted = false // <- add variable
// Get position list
db.collection('lists').doc('positions').get()
.then( res =>
let data = JSON.stringify(res.data())
data = JSON.parse(data)
if(!mounted) // <- check is it false
setPositionsList(data.list)
setLoading(false)
)
return () =>
mounted = true // <- change to true
, [])
【讨论】:
以上是关于如何取消firebase的useEffect订阅的主要内容,如果未能解决你的问题,请参考以下文章