Массив setState и получение массива React Native

Я пытаюсь установить массив в состояние, но, похоже, он не устанавливается. Я разместил часть своего кода ниже.

Я хочу, чтобы пользователь мог загрузить элемент в основную коллекцию в firestore, после чего этот элемент будет отображаться в основном списке на главном экране.

Я также хочу, чтобы пользователи могли просматривать свои собственные элементы, щелкая там собственный профиль, и они могли видеть список только этих элементов.

Я использовал подход, при котором элемент загружается в основную коллекцию в firestore, а затем идентификатор документа и ссылка на коллекцию, то есть «c», помещаются в документ в подгруппе под названием userItems, где находится в документе этого конкретного пользователя. . Я думаю, что это лучший способ сделать это, поэтому у меня есть только «1 источник истины», и мне не нужно беспокоиться о дубликатах, особенно если мне придется обновлять какие-либо документы в будущем.

Как я уже сказал вверху, моя проблема в том, что массив пуст, как только я пытаюсь перебрать его во втором методе queryUserItems. если бы кто-то смог указать, что я делаю неправильно, я был бы очень благодарен, и или если бы кто-то мог указать более элегантный и эффективный способ того, что я в конечном итоге пытаюсь сделать, а именно: Сохраняя элементы таким образом, чтобы их можно было просматривать как из основного списка, так и из собственного списка пользователя, подумайте об этом как о том, как работает Instagram.

Спасибо за любую помощь :)

UserProfile.js

constructor() {
    super();

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


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

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

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

}


getUserItems = () => {

    const Keys = [];

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




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

            querySnapshot.forEach(function (doc) {

                console.info('Doc.id: ', doc.id);
                console.info('Doc.Key: ', doc.data().Key);
                console.info('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.info("Keys inside: ", Keys);
};


queryKeys(keys) {
    const items = [];


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



    keys.forEach(function(Key, CollectionRef)  {

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

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

            console.info("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
    });

}

Обновлено:

Я решил использовать другой подход, когда я просто вызываю функцию queryKeys в конце .then в getUserItems и просто передаю ключи в качестве параметра. этот способ, похоже, работает, поскольку он получает массив в нужное время, но теперь я получаю сообщение об ошибке из firestore: Массив setState и получение массива React Native

когда я это сделаю:

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

Как получить документ по id?

Спасибо

Ваша проблема с асинхронным характером вашего кода, ваш setState вызывается до завершения цикла. Вам нужно установить состояние после того, как все элементы будут завершены

Lee Brindley 18.10.2018 17:27
getUserItems и queryKeys оба выполняют асинхронные функции. getUserItems устанавливает состояние после вызова queryKeys, поскольку он извлекает данные из внешнего источника. getUserItems должен вернуть обещание, или вы можете использовать async/await, но он должен вернуть Keys, а затем передать их queryKeys.
Max Baldwin 18.10.2018 17:30

Я попытался вызвать функцию queryKeys в функции getUserItems в конце .then после цикла for, но затем у меня возникли проблемы с вызовом функции queryKeys, я продолжал получать ошибки, говоря, что queryKeys не является функцией. хотя я чувствую, что так лучше. спасибо вам обоим за ваш комментарий

Andrew Irwin 18.10.2018 17:37
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
436
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Модификации, которые я сделал ниже, очень грязные, ваша проблема, я подозреваю, в том, что вы вызываете setState в обоих приведенных выше методах до того, как ваш цикл будет выполнен.

Вы выполняете цикл синхронно, выполняете асинхронное действие внутри цикла, выходите из цикла (синхронно) и вызываете setState, ожидая, что массивы будут заполнены данными, полученными внутри цикла, этого не произойдет, поскольку вы не ожидание запросов AJAX к firebase.

То, что я сделал ниже, - это поместил вызовы setState в разрешение обещания в каждом из ваших циклов, это не идеально (на самом деле, это ужасная идея для производства), поскольку он обновит состояние для каждого элемента в список, а не после того, как все данные были собраны. Вам нужно сделать этот цикл, есть много способов сделать это. Тем не менее, он должен продемонстрировать суть, и вы должны увидеть данные на своем экране.

constructor() {
    super();

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


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

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

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

}


getUserItems = () => {

    const Keys = [];

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




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

            querySnapshot.forEach(function (doc) {

                console.info('Doc.id: ', doc.id);
                console.info('Doc.Key: ', doc.data().Key);
                console.info('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.info("Keys inside: ", Keys);
};


queryKeys() {
    const items = [];


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



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

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

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

            console.info("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



}

Ниже вы увидите грубый пример того, как вы можете сделать цикл асинхронным, используя async и await, не зная, хорошо ли работает Firebase API с этим, вам, вероятно, придется немного почитать их документацию.

queryKeys() {
    const items = [];


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



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

        console.info("Key array: ", Key);
        console.info("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
    })

}

спасибо за ваш ответ, но я изменил свой подход, не могли бы вы показать мне, что я делаю, это вызывает ошибку из firestore

Andrew Irwin 18.10.2018 18:46

Вы изменили свой подход, поэтому вам следует создать новый вопрос, мой друг;)

Lee Brindley 18.10.2018 19:04

Другие вопросы по теме