从React类重构到React钩子时,我很难弄清楚如何更改身份验证处理组件。
这是我的班中的相关代码:
state = {
user: null
}
componentDidMount() {
authGetUser(user => {
if (user !== this.state.user) {
this.setState({user})
}
})
}
componentWillUnmount() {
authUnsubscribe()
}
handleAuthClick = () => {
if (this.state.user) {
authSignOut()
} else {
authSignIn()
}
}
这里是钩子:
const [user, setUser] = useState<firebase.User | null>(null)
useEffect(() => {
return authUnsubscribe() // runs on mount and unmount only
}, [])
useEffect(() => {
authGetUser(usr => setUser(usr))
}, [])
const handleAuthClick = () => {
if (user) {
authSignOut()
} else {
authSignIn()
}
}
另外,这是我其他相关方法:
const authGetUser = (callback: (user: firebase.User | null) => void) => {
initFirebase()
authUnsubscribe()
userUnsubscribe = firebaseAuth.onAuthStateChanged(callback)
}
export const authUnsubscribe = () => {
if (userUnsubscribe) {
userUnsubscribe()
}
}
const authSignIn = () => {
googleAuth.signIn().then((googleUser: any) => {
var credential = firebase.auth.GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token)
firebaseAuth.signInAndRetrieveDataWithCredential(credential)
})
}
const authSignOut = () => {
googleAuth
.signOut()
.then(firebaseAuth.signOut())
}
两个示例均有效。但是,当我注销并使用hooks版本登录时,在控制台中收到一条错误消息,提示
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
这表明清理未正确完成。
是的,我知道我可以继续使用适用于该类的版本。但是我想通过解决这个问题来更好地理解React挂钩。
有什么想法吗?
答案 0 :(得分:0)
这对您不起作用吗?您可以使用一个useEffect()
。
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
// Clean up the subscription
setUser(null); // <--- TRY DOING SOMETHING LIKE THIS
subscription.unsubscribe();
};
},
[],
);
清除功能在从UI删除组件之前运行 以防止内存泄漏。此外,如果一个组件呈现多个 次(通常如此),则在清除之前的效果之前 执行下一个效果。在我们的示例中,这意味着 每次更新都会创建订阅。为了避免对 每次更新,请参阅下一节。
如果您要运行效果并仅将其清理一次(在挂载和 卸载),则可以传递一个空数组([])作为第二个参数。这个 告诉React你的效果不依赖于道具的任何值 或状态,因此它不需要重新运行。这不是特殊处理 case —直接从依赖关系数组始终如何得出 有效。
答案 1 :(得分:0)
通常,当我们有异步请求并且之前未卸载组件并发生内存泄漏时,就会发生这种情况。显然,在基于类的组件中不会发生这种情况,因为我们有componentDidMount()
和componentWillUnmount()
钩子,因此比useEffect()
更自信我们已经操纵了状态,所以我认为您需要找出导致应用程序卸载的原因,并且有解决方案。
您应该使用一个useEffect()
而不是这样的两个:
useEffect(() => {
authGetUser(usr => setUser(usr))
return authUnsubscribe() // runs on mount and unmount only
}, [])