How do I ensure setState is called after the Fireb

2019-05-28 19:57发布

问题:

I am new to Firebase and using it with React Native. I am trying to populate a ListView with data from Firebase. I see that I can now use Promises in Firebase, however, it seems I cannot use them with .on() and only with .once. Because I need to listen for changes, I need to use .on().

The challenge for me now comes when I want to ensure the state is set after (and only after) the data is retrieved from Firebase. My code is below:

listen() {
    var self = this
    var currentUserID = firebase.auth().currentUser.uid
    var postList = firebase.database().ref('/users/'+currentUserID+'/postKeys')
    postList.on('value', function(snapshot) {
      var posts = []
      snapshot.forEach((child)=> {
        var postID = child.val().postID
        var postRef = firebase.database().ref('posts/'+postID)
        postRef.orderByChild('sortedDateInMilliseconds').on('value', function(postSnap) {
          posts.push(postSnap.val())          
        })

      })
      self.setState({
        postCount:posts.length,
        dataSource:self.state.dataSource.cloneWithRows(posts)
      })
    })
  }

The result is that I initially get an empty view because the render() is called before the query populates the posts array. Does anyone know how to ensure that the self.setState({}) is called after the query populates the array?

Thank you very much for your help.

回答1:

I'm not entirely sure what you mean by being called with an empty array. The only reason I can imagine is if you initially get called when there is no data yet at the location. If that is the cause, you can detect it with snapshot.exists():

listen() {
    var self = this
    var currentUserID = firebase.auth().currentUser.uid
    var postList = firebase.database().ref('/users/'+currentUserID+'/postKeys')
    postList.on('value', function(snapshot) {
      if (snapshot.exists()) {
        var posts = []
        snapshot.forEach((child)=> {
          var postID = child.val().postID
          var postRef = firebase.database().ref('posts/'+postID)
          postRef.orderByChild('sortedDateInMilliseconds').on('value', function(postSnap) {
            posts.push(postSnap.val())          
          })

        })
        self.setState({
          postCount:posts.length,
          dataSource:self.state.dataSource.cloneWithRows(posts)
        })
      }
    })
  }

If this does not fix the problem, can you set up a jsbin that reproduces it?



回答2:

You can use setTimeout function as

setTimeOut(try,3000); 
function try(){
self.setState({
        postCount:posts.length,
        dataSource:self.state.dataSource.cloneWithRows(posts)
      });
}

now self.setState({}) will be called after query if not change 3000 to 5000