Firebase onAuthStateChanged 取消订阅递归

7
我有一段代码,用于检查Firebase中的用户是否已经登录。如果是,则使用Redux发出一个动作并更新状态以表示当前授权用户。
/**
 * check to see if the user has signed in already or not
 */
function initAuth(dispatch) {
  return new Promise((resolve, reject) => {
    const unsubscribe = firebase.auth().onAuthStateChanged(
      authUser => {
        dispatch({ type: "INIT_AUTH", payload: authUser });
        unsubscribe();
        resolve();
      },
      error => reject(error)
    );
  });
}
initAuth(store.dispatch)
  .then(() => render())
  .catch(error => console.error(error));

我不太明白的是,为什么在unsubscribe()函数内部又调用了unsubscribe()函数?我知道在JavaScript中可以递归调用函数,但这里有何用处呢?谢谢!

2个回答

23

onAuthStateChanged 接受一个函数作为它唯一的参数。这个函数将在身份验证状态更改时被调用。因此,代码如下所示:

function printHelloWorld() {
    console.log("Hello World")
}

firebase.auth().onAuthStateChanged(printHelloWorld)

每当身份验证状态发生更改时,将在控制台上打印"Hello World"。但是,稍后我们希望停止执行该函数,因为我们已经完成了我们需要的操作。如果您熟悉事件侦听器,它们使用一种模式来删除事件,您可以调用类似于removeEventListener的内容。但是Firebase没有offAuthStateChanged之类的东西。相反,onAuthStateChanged函数会向您返回一个函数,以取消订阅您最初提供的函数。需要明确的是,它不会返回您的原始函数(例如此示例中的printHelloWorld),而是返回一个函数,可用于删除原始函数。

因此,回到这个例子:

function printHelloWorld() {
    console.log("Hello World")
}

var unsubscribe = firebase.auth().onAuthStateChanged(printHelloWorld)

// ... Sometime later when we are no longer interested in auth changes
unsubscribe();
// From this point forward, when the auth state changes, printHelloWorld will no longer be triggered.

最后,假设您只希望在授权更改时运行一次函数。最简单的方法是让它运行一次,然后取消订阅它。因此,代码如下:

var unsubscribe = firebase.auth().onAuthStateChanged(() => {
    console.log("Hello World")
    unsubscribe()
})

意味着在第一次身份验证状态更改时,我们将记录该字符串,然后立即取消订阅进一步更改。因此,通过在函数内部调用取消订阅,我们只是在说,运行一次,然后删除自己。

另外,请注意,您可以在函数的开头或结尾处调用取消订阅,这没关系。整个函数体将执行,就像任何其他函数一样。因此,调用取消订阅不会停止余下部分的执行,也不会影响其他操作。

这就是为什么类似于

var unsubscribe = firebase.auth().onAuthStateChanged(() => {
    unsubscribe()
    // Lots of other code here...
});

这是一个非常常见的模式。


还是不太明白哈哈...你能否尝试详细解释一下呢?比如用另一个例子来说明?如果在调用resolve之前调用unsubscribe,为什么resolve仍然有效呢? - zenoh
我在我的帖子中详细阐述了。希望这能消除任何困惑,但如果您仍有问题,请留下评论。 - CRice
1
当我从晚餐回来时看到如此详细的答案,真的让我感到惊讶,现在一切都变得清晰明了了,谢谢! - zenoh
1
“onAuthStateChanged接受一个函数作为唯一参数”在撰写时可能是正确的,但现在它需要1-3个参数:成功、错误和取消订阅。 - Collin Thomas
@nilloc 可以随意编辑答案,以反映最新版本的 Firebase 如何工作。我已经有一段时间没有使用 Firebase 了,所以我有点落后于时代。 - CRice
非常好的回答!非常感谢您对此进行了详细阐述!! - gignu

6

如果您想仅一次性监听用户身份验证状态的更改,可以按照以下方式操作:

const unsubscribe = firebase.auth().onAuthStateChanged((user) => { 
    if(unsubscribe) {
      unsubscribe();
    }
 }

听众似乎运行了两次,第一次是在创建时,第二次是当用户实际更改状态时。在第一次中,unsubscribe未定义,因此您需要在运行之前检查是否已定义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接