Andrew Irwin
Andrew Irwin

Reputation: 711

Array setState and get array React Native

I'm trying to set an array into state, but it doesn't appear to be getting set. I have posted some of my code below.

What I am looking to do is, a user can upload an item to the main collection on firestore, this item will then be shown on the main list, on the main screen.

I also want users to be able to view their own items by they clicking on there own profile and they can see a list of only there items.

I have taken the approach that the item gets uploaded to the main collection on firestore, and then the doc id, and collection reference i.e "c" both get put into a doc in a sub-collection called userItems with is in that specific user's doc. I think this is the best way to do it, so I only have "1 source of truth" and not having to worry about duplicates, especially if I have to update any documents in the future.

As I have said at the top, my problem is the array is empty once I try to iterate through it in the 2nd method "queryUserItems". if someone one would be able to point out what I am doing wrong I would be very grateful, and or if someone might be able to point out a more elegant and efficient way of what I'm ultimately trying to do, that is: saving the items in a way that they can be viewed from the main list as well as the user own list, think of it a bit like how Instagram works.

Thank you for any help :)

UserProfile.js

constructor() {
    super();

    this.getUserItems = this.getUserItems.bind(this);


    this.state = {
        Name: '',
        Location: '',
        items: [],
        Keys: [],
        test: ''
    };
}

componentDidMount() {
    console.log('UserProfile');

    this.getUserItems();
    //this.queryKeys();

}


getUserItems = () => {

    const Keys = [];

    const userCollectionRef = firebase.firestore()
        .collection('a').doc('b')
        .collection('c')




    userCollectionRef.get()
        .then((querySnapshot) => {
            console.log("user doc received");

            querySnapshot.forEach(function (doc) {

                console.log('Doc.id: ', doc.id);
                console.log('Doc.Key: ', doc.data().Key);
                console.log('Doc.CollectionRef: ', doc.data().CollectionRef);

                const {Key, CollectionRef} = doc.data();

                Keys.push({
                    Key,
                    CollectionRef
                })

            }); // foreach loop end
this.queryKeys(keys);




        }).catch(function (error) {
        console.error("getUserItems => error: ", error);
    });

  //  this.setState(() =>({
    //    Keys,
      //  test: 'testString'
   // }));

    console.log("Keys inside: ", Keys);
};


queryKeys(keys) {
    const items = [];


    console.log("queryKeys Called!");
    console.log("queryKeys :", keys);
    console.log('test: ', this.test);



    keys.forEach(function(Key, CollectionRef)  {

        console.log("Key array: ", Key);
        console.log("CollectionRef array: ", CollectionRef);

        firebase.firestore
            .collection('a').doc('b')
            .collection(CollectionRef)
            .doc(Key)
            .get().then(function (doc) {

            console.log("doc received");

            const {Name, imageDownloadUrl, Location} = doc.data();

            items.push({
                key: doc.id,
                doc, // DocumentSnapshot
                Name,
                imageDownloadUrl,
                Location,
            });

        }).catch(function (error) {
            console.error("queryKeys: error: ", error);
        })

    }) // forEach end

    this.setState({
        items
    });

}

UPDATE:

I have decided to take a different approach, where I just call the queryKeys function at the end of the .then in getUserItems and just pass in the keys as a parameter. this way appears to work as it gets the array in at the right time, but now Im getting an error from firestore: firestore error

when I do this :

firebase.firestore
        .collection('a').doc('b')
        .collection('c')
        .doc('docID').get()
        .then((doc) => {

How can I get a document by id ?

Thank you

Upvotes: 0

Views: 516

Answers (1)

Lee Brindley
Lee Brindley

Reputation: 6482

The modifications i've made below are super dirty, your problem i suspect is that you're calling setState in both your methods above, before your loop has executed.

You're looping synchronously, performing an asyncronous action inside the loop, exiting the loop (syncronously), and calling setState, expecting the arrays to be filled with the data fetched inside the loop, this won't happen, as you're not waiting on the AJAX requests to firebase.

What i've done below is put the calls to setState inside the resolve of the promise in each of your loops, this is not ideal (in-fact, it's a terrible idea for production), as it will update state for every item in the list, rather than once all data has been collected. You need to make that loop there are many ways of doing that. It should demonstrate the point though, and you should see data on your screen.

constructor() {
    super();

    this.getUserItems = this.getUserItems.bind(this);


    this.state = {
        Name: '',
        Location: '',
        items: [],
        Keys: [],
        test: ''
    };
}

componentDidMount() {
    console.log('UserProfile');

    this.getUserItems();
    this.queryKeys();

}


getUserItems = () => {

    const Keys = [];

    const userCollectionRef = firebase.firestore()
        .collection('a').doc('b')
        .collection('c')




    userCollectionRef.get()
        .then((querySnapshot) => {
            console.log("user doc received");

            querySnapshot.forEach(function (doc) {

                console.log('Doc.id: ', doc.id);
                console.log('Doc.Key: ', doc.data().Key);
                console.log('Doc.CollectionRef: ', doc.data().CollectionRef);

                const {Key, CollectionRef} = doc.data();

                Keys.push({
                    Key,
                    CollectionRef
                })


            });

              this.setState(() =>({
                    Keys,
                    test: 'testString'
                }));

        }).catch(function (error) {
        console.error("getUserItems => error: ", error);
    });



    console.log("Keys inside: ", Keys);
};


queryKeys() {
    const items = [];


    console.log("queryKeys Called!");
    console.log("queryKeys :", this.state.Keys);
    console.log('test: ', this.test);



    this.state.Keys.forEach(function(Key, CollectionRef)  {

        console.log("Key array: ", Key);
        console.log("CollectionRef array: ", CollectionRef);

        firebase.firestore
            .collection('a').doc('b')
            .collection(CollectionRef)
            .doc(Key)
            .get().then(function (doc) {

            console.log("doc received");

            const {Name, imageDownloadUrl, Location} = doc.data();

            items.push({
                key: doc.id,
                doc, // DocumentSnapshot
                Name,
                imageDownloadUrl,
                Location,
            });

         this.setState({
             items
         });

        }).catch(function (error) {
            console.error("queryKeys: error: ", error);
        })

    }) // forEach end



}

Below you'll see a rough example of how you could make the loop asyncronous, using async & await, unsure if Firebase API plays well with this, you will probably need to do a little reading on their docs.

queryKeys() {
    const items = [];


    console.log("queryKeys Called!");
    console.log("queryKeys :", this.state.Keys);
    console.log('test: ', this.test);



    this.state.Keys.forEach(async function(Key, CollectionRef)  {

        console.log("Key array: ", Key);
        console.log("CollectionRef array: ", CollectionRef);

        try {
            let result = await firebase.firestore
            .collection('a').doc('b')
            .collection(CollectionRef)
            .doc(Key)
            .get();


            const {Name, imageDownloadUrl, Location} = result.data();

            items.push({
                key: doc.id,
                doc, // DocumentSnapshot
                Name,
                imageDownloadUrl,
                Location,
            });
        } catch (e) {
            console.error("queryKeys: error: ", error);
        }
    }) // forEach end


    this.setState({
        items
    })

}

Upvotes: 1

Related Questions