Я пытаюсь установить массив в состояние, но, похоже, он не устанавливается. Я разместил часть своего кода ниже.
Я хочу, чтобы пользователь мог загрузить элемент в основную коллекцию в 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:

когда я это сделаю:
firebase.firestore
.collection('a').doc('b')
.collection('c')
.doc('docID').get()
.then((doc) => {
Как получить документ по id?
Спасибо
getUserItems и queryKeys оба выполняют асинхронные функции. getUserItems устанавливает состояние после вызова queryKeys, поскольку он извлекает данные из внешнего источника. getUserItems должен вернуть обещание, или вы можете использовать async/await, но он должен вернуть Keys, а затем передать их queryKeys.
Я попытался вызвать функцию queryKeys в функции getUserItems в конце .then после цикла for, но затем у меня возникли проблемы с вызовом функции queryKeys, я продолжал получать ошибки, говоря, что queryKeys не является функцией. хотя я чувствую, что так лучше. спасибо вам обоим за ваш комментарий



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Модификации, которые я сделал ниже, очень грязные, ваша проблема, я подозреваю, в том, что вы вызываете 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
Вы изменили свой подход, поэтому вам следует создать новый вопрос, мой друг;)
Ваша проблема с асинхронным характером вашего кода, ваш setState вызывается до завершения цикла. Вам нужно установить состояние после того, как все элементы будут завершены