0

Someone please help. I have combed all of the doc's, examined all similar questions and really cannot see what I am missing.

I am new to react and trying to map over documents returned from an asynchronous call from a firebase db.

Here is the code:

class Posts extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        data: [],
    };
}
componentDidMount() {
    let posts = [];
    db.collection("Posts").get().then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            posts.push({
                data: doc.data(),
                id: doc.id
            });
        });
    });
    this.setState({
        data: posts
    });
}
renderPosts() {
    console.log(this.state.data);
    return this.state.data.map((post, index) => {
        console.log(post);
        console.log(index);
        return (
            <div>
                {index}
            </div>
        )
    })
}
render() {
    return(
        <div>
            {this.renderPosts()}
        </div>
    );
}
}

I am sure it is something super simple but I am pulling my hair out. If I examine my state I can see the data. console.log(this.state.data); inside renderPosts even displays exactly what I need to map over, but everything inside the map callback doesn't return and I end up with a single empty Any help would be greatly appreciated.

3
  • 1
    I assume getting data from Firebase is async right? So that means posts.push in the then of the request promise is running after setState. Commented Aug 6, 2018 at 3:58
  • Instead, set stare inside the then callback, and instead of forEaching and pushing, use map. Make sure to use the right this by converting the callback to an arrow function Commented Aug 6, 2018 at 4:00
  • Yes it's asynchronous. Commented Aug 6, 2018 at 4:01

1 Answer 1

2

As Li357 commented, the setState call needs to happen inside the get() callback:

db.collection("Posts").get().then(function(querySnapshot) {
    querySnapshot.forEach(function(doc) {
        posts.push({
            data: doc.data(),
            id: doc.id
        });
    });
    this.setState({
        data: posts
    });
});

The reason for this is that data is loaded from Firestore asynchronously, and by the time you were calling setState the posts variable was still empty.

The easiest way to understand this type of asynchronous loading is with a few log lines:

console.log("Before starting to get documents");
db.collection("Posts").get().then(function(querySnapshot) {
    console.log("Got documents");
});
console.log("After starting to get documents");

When you run this, the output is:

Before starting to get documents

After starting to get documents

Got documents

That is probably not the order you expected the output in. But it is the expected behavior: instead of blocking the code while the data is loaded (which would freeze the browser), the code after the get().then() block immediately executes. And then when the data is loaded, the code in the then callback is executed. That's why all code that needs the documents from the database needs to be inside the then callback.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks Frank - I am confused then as to why in my example above when I log the state inside renderPosts() I have the data I need. If my console.log function inside of renderPosts() runs in the place of your "After starting to get the documents" in your explaination then shouldn't it be blank since state hasn't been updated yet?
Most likely it's an artifact of how Chrome logs objects: they are "live" and not snapshot. Try logging console.log(this.state.data.length); and I expect that is to still be 0.
Ah yes - it is 0
Thanks for the help, can't upvote b/c I don't have enough points - really appreciate the help
@Li357 the QuerySnapshot does not have a map method: firebase.google.com/docs/reference/js/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.