0

在我的以 firebase 作为后端的 react-native 应用程序中,我有一个像这样的初始 LoginScreen:(react-navigation 的导航功能呈现作为第一个参数传递的屏幕,作为 props.navigation.params.state 传递给该屏幕的第二个参数)

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)
    ...

和一个 MainApp 组件作为 react-navigation tabNavigator,屏幕“配置文件”看起来像:

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)}
                 />}
    ...

启动应用程序时,侦听器第一次感知到用户的存在时,它会导航到 MainApp 屏幕,但会出现警告,组件 Profile 的渲染函数中的 {this.state.currentUser.user} 未定义; 但是当我浏览 tabBar 时,我可以看到该用户名,但 ListView 是空的。如果我刷新,将检索 firebase 数据并填充 ListView。

如果我注销并重新登录没有再次发生,数据会立即加载,不会出现警告,并且会立即填充列表视图。

如果我退出并重新启动应用程序,因为已经有一个登录用户,它会导航到 MainApp 屏幕,但是如果我注销并重新登录一切正常,上面会出现同样的问题。

请问,我的错误是什么?有谁能够帮我?

4

1 回答 1

0

问题是加载 onAuthStateChanged 时,currentUser 仍然为空。但是,如果您等待一段时间并稍后尝试(例如,相同的代码,但在另一个屏幕中),一切都会正常工作。这就是为什么你的第二次尝试没有错误的原因。

对于我使用 setInterval 函数的旁路——它会自行执行,直到它检索到 currentUser 对象

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);

另外,请注意获取 currentUser.uid 不是一个好主意,它应该先等待 currentUser,然后再获取其属性。希望您没有等待太久,并且已经找到了解决方案。

于 2017-05-07T15:27:36.167 回答