Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialAaron Watkins
10,902 PointsFirebase promises
Hello all!
I am using firebase as a backend and querying it to populate a list in React Native. The data structure follows the firefeed example (https://firefeed.io/about.html), where all of the posts are stored in a global node in firebase and each user stores a reference key to their profile. Flow is like this:
- user creates post and saves it to global posts node
- a reference key is stored to user's profile
- a reference key is stored to feed node organized by ID for all of the users followers.
The challenge i have is that I am trying to render the list, but it's coming back as a "seemingly" empty array. When I console.log it out, the array is an empty bracket and the length of the array is 0. However, when I click the arrow, I see the desired data.
I believe this has to do with order of execution.
The code is:
listen() {
var self = this
// get current user ID
var currentUserID = firebase.auth().currentUser.uid
// query user class to get reference keys to posts
var postList = firebase.database().ref('/users/'+currentUserID+'/postKeys')
//create posts array to store posts that are queried
var posts = []
// query the post class
postList.once('value').then(function(snapshot) {
snapshot.forEach((child)=> {
// get postID
var postID = child.val().postID
// append postID to get location of post data
var postRef = firebase.database().ref('posts/'+postID)
// get post data
postRef.once('value').then(function(postSnap) {
// save data to variable post
post = postSnap.val()
push post object to array
posts.push(post)
// setState here returns desired value, but probably bad practice because I set the state as many times as there are posts.
})
}) //.then here returns error
}) // .then here returns empty array
}
Any help with this would be greatly appreciated. Thank you
3 Answers
Joseph Dalton
12,489 PointsAwesome! I'm glad I could help Aaron.
About using on()
instead of once()
, it looks like the on()
method does not return a promise object like once()
method, or the other methods mentioned in the blog post. I also checked the Firebase docs for on()
(here), and it looks like, just like you said, you'll have to go back to using callbacks if you need to keep watching the event.
Aaron Watkins
10,902 PointsJoseph Dalton - absolutely incredible...thank you. One more question for you now that this approach works (and thanks for explaining the empty array in the console situation...that boggled my mind). I need to listen for changes when a new post is added to update the feed. I'm unclear from this post (https://firebase.googleblog.com/2016/01/keeping-our-promises-and-callbacks_76.html), why I cannot use .on instead of .once. In all of the examples where people are using Firebase promises it appears they are using .once, however .on is needed in my case. Would this mean I need to resort to a callback instead of a promise?
thanks again for your help. I really appreciate it.
Aaron Watkins
10,902 PointsJoseph Dalton you're amazing. thanks a million.
Joseph Dalton
12,489 PointsJoseph Dalton
12,489 PointsHey Aaron,
First, I think your
console.log()
confusion is just coming from the promises not yet being fulfilled when console.loggingposts
. I am guessing that when you first log theposts
array, the calls to the database are still pending (thepostRef
promises), however theposts
array has already been created, so it initially gets logged as empty. But with objects and arrays, the console usually logs a reference to the object, not a snapshot of it, so as the object or array gets updated in your logic, it will eventually be reflected in the console's log (I think until you expand it). So while it looks empty at first, by the time you expand it, the promises have been fulfilled and the values are present.To see a snapshot of the array in the console, you could make a copy of it when logging it (via calling
arr.slice(0)
), or by usingJSON.stringify(arr)
to print a string.So, this leads to working with the filled
posts
array. If you are trying to use it at the same time as your empty console.log call, then you probably need to wait until thepostRef
promises have all been fulfilled. This can be done with...another promise!I noticed you are using an arrow function above, so I'll assume you are also open to using ES6 promises. This might be one solution:
Hope that helps!