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