【问题标题】:return a cleanup function returning form the async function in userEffect in react Native在react Native中从useEffect中的异步函数返回一个清理函数
【发布时间】:2020-12-12 07:22:13
【问题描述】:

我正在使用 firebase onSnapshot 方法在 react 本机应用程序中使用实时数据,并编写了一个单独的异步函数来监听 firestore,如下所示,

async function getData() {

    let collName = await AsyncStorage.getItem('@collection_name')
    let subscriber = shopReference.collection(collName).onSnapshot((snap) => {
        let menuList = [];
        snap.forEach((doc) => {
          menuList.push({
            id: doc.id,
            ...doc.data(),
          });
        });
    
        setMenu(menuList);
      });

      return subscriber;
}

我正在使用 useEffect 调用此函数,并且我想返回从 firestore 返回的订阅者方法作为清理函数。我知道我可以通过在 useEffect 函数中直接实现这段代码来实现这一点。但是由于我使用 AsyncStorage 来检索集合 id,因此我需要将其放在异步函数中。我无法返回 getData() 方法的响应,因为它返回的是 promise 而不是订阅者函数。解决此问题的最佳解决方案是什么?

编辑

我尝试了以下所有方法来调用 useEffect 函数中的函数。

// Without returning anything, but according to the firestore doc. This may cause data leaks.
useEffect(() => {
        getData();
      }, []);

// directly returning the method, this cause error that promise cant be accepted as a clean up function.
useEffect(() => {
        return getData();
      }, []);



useEffect(() => {
        getData().then((subscriber) => {
             return () => subscriber();
        });
      }, []);

【问题讨论】:

  • 返回一个清理函数,该函数仅在订阅者准备好后使用,如果在 getItem 完成之前调用,甚至阻止创建订阅者。
  • @Bergi 如果在 getItem 完成之前调用会阻止订阅者的创建,这就是我使用异步函数并等待 AsyncStorage 的结果的原因。我面临的问题是如何返回订阅者函数,因为方法返回承诺。
  • 您无法得到比getData 对订阅者功能的承诺更好的东西。请告诉我们你是怎么称呼它的useEffect虽然
  • 我用useEffect编辑了代码

标签: javascript reactjs firebase react-native promise


【解决方案1】:

您不能更改 getData 以立即返回清理函数。你宁愿使用

useEffect(() => {
    let subscriber = () => {};
    getData().then(sub => {
         subscriber = sub;
    });
    return () => {
         subscriber();
    };
}, []);

useEffect(() => {
    const subscriberPromise = getData();
    return async () => {
         const subscriber = await subscriberPromise;
         subscriber();
    };
}, []);

但是,当清理函数在承诺完成之前被调用时,这些并不理想(更不用说错误处理......)。虽然第一个在这种情况下根本不起作用,但第二个仍然不必要地启动订阅。为了正确地做到这一点,我建议像

useEffect(() => {
    let cleanup = () => {};
    AsyncStorage.getItem('@collection_name').then(collName => {
        if (!cleanup) return; // already cancelled
//      ^^^^^^^^^^^^^^^^^^^^
        cleanup = shopReference.collection(collName).onSnapshot((snap) => {
            let menuList = [];
            snap.forEach((doc) => {
                menuList.push({
                    id: doc.id,
                    ...doc.data(),
                });
            });
            setMenu(menuList);
        });
    });

    return () => {
         cleanup();
         cleanup = null;
    };
}, []);

【讨论】:

    猜你喜欢
    • 2020-12-22
    • 2020-08-08
    • 2023-02-04
    • 2022-01-26
    • 1970-01-01
    • 2020-09-02
    • 1970-01-01
    相关资源
    最近更新 更多