如何在反应中删除新的 firebase onAuthStateChanged 侦听器

How to remove the new firebase onAuthStateChanged listener in react

我正在使用 react-router 在 React 网络应用程序中实施 firebase 身份验证。

用户使用 Facebook 或 Google 使用弹出式登录登录(在 /signin),然后如果成功,我将路由到主应用程序 (/)。在主应用程序组件中,我监听身份验证状态更改:

  componentWillMount() {
    this.authListener = this.authListener.bind(this);
    this.authListener();
  }

authListener 侦听身份验证更改:

authListener() {
    firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        console.log('user changed..', user);
        this.setState({
          User: {
            displayName: user.displayName
          }
        });
      } else {
        // No user is signed in.
        browserHistory.push('/signin');
      }
    });
  }

一切正常,除非我注销(并返回 /signin)并使用 facebook 或 google 再次登录。然后我收到一条错误消息:

Warning: setState(...): Can only update a mounted or mounting component.

我怀疑来自现在卸载的先前登录状态应用程序的 onAuthStateChanged 侦听器仍然是 运行。

有没有办法在 App 组件卸载时删除 onAuthStateChanged 监听器?

您设置的任何侦听器也需要拆除。

你的怀疑非常切合实际。

您应该使用 componentWillUnmount 生命周期方法来删除任何可能污染您的应用程序的剩余侦听器。

清除监听器,相关代码如下:

在您的 authListener 函数中,您需要在组件中保存对侦听器的引用(调用 firebase.auth().onAuthStateChanged 后返回给您)。这将是一个钩子,它将取消引用侦听器并将其删除。

因此,与其调用它,不如将返回值原样保存

this.fireBaseListener = firebase.auth().onAuthStateChanged ...

当您的组件卸载时,使用此代码:

componentWillUnmount() {
   this.fireBaseListener && this.fireBaseListener();
   this.authListener = undefined;
}

@Justin 因为 onAuthStateChanged returns 函数所以你可以用它来清除监听器... this.fireBaseListener = firebase.auth().onAuthStateChanged

文档:https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged

Returns non-null firebase.Promise containing non-null Array of string

您可以像这样检查订阅,而不是在 componentDidMount() 中检查 onAuthStateChanged() 函数。

componentWillMount() {
    //following line will help you to setState() but not required
    let set =  this  

    //this is our trick
    this.unsubscribe  = firebase.auth().onAuthStateChanged(user => {
        if (!user) {
            //navigate to guest stack
            //actually im using react-navigation
            set.props.navigation.navigate('Guest'); 
        } else {
            //set current user to state 
            set.setState({
                user: user,
                loading: false
            })
        }
    });
}

//What you have to do next is unsubscribe ;) 
componentWillUnmount() {
    this.unsubscribe();
}

我知道我来晚了,但这里有一个基于钩子的解决方案:

React.useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged((user) => { // detaching the listener
        if (user) {
            // ...your code to handle authenticated users. 
        } else {
            // No user is signed in...code to handle unauthenticated users. 
        }
    });
    return () => unsubscribe(); // unsubscribing from the listener when the component is unmounting. 
}, []);

如果您使用的是 Firebase 9,您应该注意调用函数的方式 onAuthStateChanged

第一种方式

import firebaseApp from 'path/to/your/firebase/app';
// you will need to do 
const auth = getAuth(firebaseApp);

useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged(user => {
        if (user) {
            // user is signed in
        } else {
            // user is signed out
        }
    });
    
    // unsubscribing from the listener when the component is unmounting.
    return unsubscribe;
}, [])

第二种方式

import firebaseApp from 'path/to/your/firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
const auth = getAuth(firebaseApp);


useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
        ...
    });
    
    // unsubscribing from the listener when the component is unmounting.
    return unsubscribe;
}, [])