【问题标题】:how to cancel useEffect subscriptions of firebase如何取消firebase的useEffect订阅
【发布时间】: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
    }, [])

【问题讨论】:

  • 您在未安装的组件上更改了没有意义的状态,您会收到警告。
  • 你能解释更多吗?

标签: reactjs firebase google-cloud-firestore react-hooks use-effect


【解决方案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 
              }
          }, [])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-06
        • 1970-01-01
        • 2020-12-05
        • 2022-01-19
        • 2012-03-14
        • 1970-01-01
        • 1970-01-01
        • 2018-04-13
        相关资源
        最近更新 更多