Firebase 身份验证和 React Hook - 从钩子返回的函数不起作用

Firebase auth and React Hook - returning function from hook not working

我有一个自定义身份验证挂钩,用于提供用户和加载状态,以及一些基于用户的操作(例如注销)。这是我的代码:

type UserActions = {
  signOut(): Promise<void>;
};

const useUser = (): [
  firebase.User | undefined | null,
  UserActions,
  boolean,
  firebase.auth.Error | undefined
] => {
  const auth = firebase.auth();
  const [firebaseUser, loading, error] = useAuthState(auth);

  return [firebaseUser, { signOut: firebase.auth().signOut }, loading, error];
};

export default useUser;

调用钩子后在另一个文件中使用signOut()函数时,出现错误Unhandled Rejection (TypeError): Cannot read property 'then' of undefined

然而,当我简单地改变我的钩子时:

type UserActions = {
  signOut(): Promise<void>;
};

const useUser = (): [
  firebase.User | undefined | null,
  UserActions,
  boolean,
  firebase.auth.Error | undefined
] => {
  const auth = firebase.auth();
  const [firebaseUser, loading, error] = useAuthState(auth);

  const signOut = () => {
    return firebase.auth().signOut();
  };
  return [firebaseUser, { signOut }, loading, error];
};

export default useUser;

效果很好。这两种情况有什么区别?不确定我是否遗漏了有关箭头功能如何工作的内容,或者可能与键入有关的内容?

谢谢!

这是因为您更改了 implementation of signOut() 所需的 this 的上下文(为简洁起见删除了注释):

fireauth.Auth.prototype.signOut = function() {
  var self = this;
  var p = this.redirectStateIsReady_.then(function() {
    if (self.authEventManager_) {
      self.authEventManager_.clearRedirectResult();
    }
    
    /* ... */
  }
  
  return this.registerPendingPromise_(p);
}

在您的第一次尝试中,您使用:

{ signOut: firebase.auth().signOut }

有效创建:

{
  signOut() {
    var self = this;
    var p = this.redirectStateIsReady_.then(function() {
      if (self.authEventManager_) {
        self.authEventManager_.clearRedirectResult();
      }
    
      /* ... */
    }
  
    return this.registerPendingPromise_(p);
  }
}

在该代码块中,this(和 self)不再是 FirebaseAuth class 的实例,而是您的对象具有 { signOut: () => Promise<void> }。当您调用 signOut() 时会引发错误,因为该对象上不存在 redirectStateIsReady_authEventManager_ 等属性(它们将是 undefined)。

这个错误:

Unhandled Rejection (TypeError): Cannot read property 'then' of undefined

被抛出是因为 yourObject.redirectStateIsReady_undefined,这意味着代码尝试(但失败)调用 (undefined).then().

在您的第二次(简化)尝试中,您使用:

const signOut = () => firebase.auth().signOut();

在这种情况下,signOut 方法没有从它的 FirebaseAuth class 中分离出来,并按预期运行。这被称为“绑定”一个函数,在箭头函数使它变得更容易之前,这是使用:

const obj = firebase.auth();
const signOut = obj.signOut.bind(obj);