如何成功取消订阅用户通知(firebase,react)

Posted

技术标签:

【中文标题】如何成功取消订阅用户通知(firebase,react)【英文标题】:How can I successfully unsubscribe from user notfiications (firebase, react) 【发布时间】:2021-08-27 22:05:05 【问题描述】:

我的用户在他们的userData 文档中有一个名为notifications 的集合。我想实时收听这些内容,以便您可以立即看到通知(如任何社交媒体应用、facebook instagram 等)。

在我的 app.js 中,我目前有这个 useEffect:

  useEffect(() => 
    //this gets the user data
    const unsubscribeUserData = async () => 
          const userData = await getUserByUserId(currentUser.uid);
          setData(userData);
    ;
    //this subscribes to their notifications
  
    /* 
    //This the unsub method
    const unsubscribe = db
      .collection("users")
      .doc(currentUser.uid)
      .collection("notifications")
      .orderBy("date", "desc")
      .onSnapshot((snapshot) => 
        let tempNotifications = [];
        snapshot.forEach((notification) => 
          console.log("adding notification: ", notification);
          tempNotifications.push(notification.data());
        );
        setNotifications(tempNotifications);
      );
    */
    
    
    //What do I do with useRef?
    const unsubscribe = useRef();
   
    if (currentUser) 
      //If there is an auth object stored in my auth context, get their data and subscribe to their notifications
      unsubscribeUserData();
      unsubscribe();
     else 
      //If there isn't, unsub from the notifications and set data to null
      setData(null);
      unsubscribe();
    
    return () => 
      //If they have closed the webpage, unubscribe
      unsubscribe();
    ;
  , [currentUser]);

谁能给我一个关于如何构建它以便在需要时成功取消订阅的提示?

谢谢!

编辑(我相信这可行!)

  useEffect(() => 
    const getUserData = async () => 
      const userData = await getUserByUserId(currentUser.uid);
      setData(userData);
    ;

    if (currentUser) 
      getUserData();

      return (unsubscribeRef.current = db
        .collection("users")
        .doc(currentUser.uid)
        .collection("notifications")
        .orderBy("date", "desc")
        .onSnapshot((snapshot) => 
          let tempNotifications = [];
          snapshot.forEach((notification) => 
            console.log("adding notification: ", notification);
            tempNotifications.push(notification.data());
          );
          setNotifications(tempNotifications);
        ));
     else 
      setData(null);
    
  , [currentUser]);

我相信在实际快照侦听器处调用 return 与调用 cleanup return 相同,但是在这里执行此操作会跳过 not a function 错误

【问题讨论】:

useEffect钩子回调不能是async。我不知道这是否是您的问题的原因,但它肯定对您没有帮助。 感谢您的回复,啊,我明白了,很奇怪。如何等待 getUserbyUserId() 的结果? @DrewReese 您需要获取整个回调并在同步挂钩回调中定义它,然后调用它。不过这里的问题是你仍然需要从钩子回调中返回一个清理函数来取消订阅。我会尝试使用 React ref 来保存对取消订阅函数的引用,以便在清理函数中调用。 @DrewReese 好的,太棒了,谢谢,我看看,你是说 useRef 钩子吗? 肯定,createRef 对于功能组件的工作方式并不完全相同。 【参考方案1】:

主要问题是 useEffect 钩子回调不能是 async 函数,因为它们隐式返回一个 Promise,根据设计,它会被解释为 useEffect 钩子清理函数。这行不通。

稍微查看一下您的代码后,似乎获取和设置data 状态与firebase 订阅无关。您可以仅将异步逻辑缩小到 async 函数中,以获取和设置用户数据并调用它,然后照常访问 firebase 集合。

使用 React ref 保持 unsubscribe 回调。

我认为以下实现应该让您非常接近您正在寻找的东西。 (免责声明:我没有测试过这段代码,但我认为它应该可以工作

const unsubscribeRef = useRef();

useEffect(() => 
  const getUserData = async () => 
    const userData = await getUserByUserId(currentUser.uid);
    setData(userData);
  ;

  if (currentUser) 
    getUserData();

    unsubscribeRef.current = db
      .collection("users")
      .doc(currentUser.uid)
      .collection("notifications")
      .orderBy("date", "desc")
      .onSnapshot((snapshot) => 
        let tempNotifications = [];
        snapshot.forEach((notification) => 
          console.log("adding notification: ", notification);
          tempNotifications.push(notification.data());
        );
        setNotifications(tempNotifications);
      );
   else 
    setData(null);
  

  return () => 
    // Unsubscribe any current subscriptions before rerender/unmount
    // Note: uses Optional Chaining operator, if this can't work for you
    // use normal null-check:
    //   unsubscribeRef.current && unsubscribeRef.current()
    unsubscribeRef?.current();
  ;
, [currentUser]);
    

【讨论】:

您好,感谢您的评论!我收到一个错误:TypeError: unsubscribeRef.current(...) is not a function @squish 您在调用之前是否缺少选项链运算符 (?.)? IE。 unsubscribeRef?.current() 而不是 unsubscribeRef.current()。如果您无法转译此代码,请尝试使用传统的 null 检查,即unsubscribeRef.current && unsubscribeRef.current() 我想我可能有一个可行的解决方案!它是你的,略有变化。生病现在编辑我的帖子! @squish 不用担心,就像我说的那样,我无法对其进行测试,但我认为它会让你顺利完成 99% 的工作。

以上是关于如何成功取消订阅用户通知(firebase,react)的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 云消息传递为已取消订阅的令牌返回 200 OK

您如何向从应用程序本身订阅主题的用户发送 Firebase 推送通知

Flutter Firebase Cloud Messaging 如何自动关闭/取消通知?

AngularFire2:通过多个浏览器选项卡通知注销

Google Firebase 通知无法订阅主题

如何从 React Native Expo 推送通知中取消订阅(删除监听器)