简体   繁体   中英

react native firebase onAuthStateChanged

In my react-native app with firebase as backend I've got an initial LoginScreen like this: ( the react-navigation's navigate function renders the screen passed as first argument passing as props.navigation.params.state the second argument to that screen )

class LoginScreen extends Component {

    constructor() {
        this.state = {
            currentUser: {},
            email: null,
            psw: null

...

async logIn(email, pass) {
  try {
      await firebaseApp.auth()
          .signInWithEmailAndPassword(email, pass)
  } catch (error) {
      alert(error.toString())
  }
}

listenForAuth() {
    const { navigation } = this.props
    this.unsubscribe = firebase.auth().onAuthStateChanged(user => {
        if (user) {
            this.setState({
                currentUser: {
                    id: user.uid
                }
            })
            navigation.navigate('MainApp', { currentUser: this.state.currentUser })
        } else {
            this.setState({
                loading: false
            })
        }
    })
}

componentWillMount() {
    this.listenForAuth()
}

render() {
    ...
    <LoginButton onPress={() => this.logIn(this.state.email,this.state.psw)
    ...

and a MainApp component as a react-navigation tabNavigator, with the screen 'Profile' that looks like:

class Profile extends Component {

    constructor(props) {
        super(props)
        const { currentUser } = this.props.navigation.state.params
        this.userRef = firebaseApp.database().ref( 'users/' + currentUser.id )
        this.postsRef = firebaseApp.database().ref( 'users/' + currentUser.id + '/myposts' )
        this.state = {
            currentUser: {},
            refreshing: false,
            postsDataSource: new ListView.DataSource({
                rowHasChanged: (row1, row2) => row1 !== row2,
            })
        }
    ...
    listenForUser(usersRef) {
       usersRef.on('value', snap => {
          this.setState({
            currentUser: {
              user: snap.val().user,
              photo: snap.val().photo,
              email: snap.val().email,
              id: snap.val().id
           }
         })
       })

  listenForPosts(postsRef) {
  postsRef.on('value', snap => {
    var posts = []
    snap.forEach( trip => {
      firebaseApp.database().ref( 'posts/' + posts.key ).on('value', child => {
          posts.push({
            title: child.val().title,
            own: child.val().own,
            _key: child.key
          })
       })
    })
    this.setState({
      postsDataSource: this.state.postsDataSource.cloneWithRows(posts)
    })
   })
  }

  componentDidMount() {
     this.listenForUser(this.userRef)
     this.listenForPosts(this.postsRef)
  }

  _onRefresh() {
     this.setState({ refreshing: true })
     this.listenForPosts(this.postsRef)
     this.setState({ refreshing: false })
  }
  ...
  render() {
    ...
    <Text>{this.state.currentUser.user}</Text>
    ...
    <ListView dataSource={this.state.postsDataSource} 
              refreshControl={
                 <RefreshControl
                    refreshing={this.state.refreshing}
                    onRefresh={this._onRefresh.bind(this)}
                 />}
    ...

When the app is launched, the first time that the listener senses the presence of a user, it navigates to the MainApp screen but a warning appears, the {this.state.currentUser.user} in the render function of the component Profile it's undefined; but when I navigate through the tabBar I can see that username but the ListView is empty. If I refresh, the firebase data is retrieved and the ListView is populated.

if I logout and relogin does not happen again, the data is immediately loaded, no warning appears and listview is immediately populated.

If I quit and restart the app, since there's already a logged in user, it navigates to MainApp screen but there's the same problem seen above, if I logout and relogin everything works.

Please, what's my mistake? Can anybody help me?

The problem is that when onAuthStateChanged is loaded, currentUser is still null. However, if you wait for some time and try later (for example, the same code, but in another screen) everything will work. That is why there is no mistake on your second attempt.

For the bypass I was using setInterval function -- it will execute itself, until it retrieves currentUser object

let renderAction = setInterval(() => {
        if ( firebase.auth().currentUser !== null ) {
            clearInterval(renderAction);
            let user = firebase.auth().currentUser;
            let uid = user.uid;
            this.setState({uid});
        } else {
          console.log('Wait for it');
        }
      }, 500);

Also, note that it is not a good idea to get currentUser.uid, it should wait for currentUser first and then get its properties. Hope you have not been waiting for too long and have already found a solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM