# #javascript #firebase #react-native #google-cloud-firestore
Вопрос:
Так что это действительно странно
это мой код, когда он работает
useEffect(() => {
// Alleen preview
async function getTracksData() {
let TrackData = await firebase
.firestore()
.collection('TrackScreen')
.doc('LeerjarenData')
.get();
if (!TrackData.exists) {
console.log('Geen data')
} else {
let TrackDatav2 = TrackData.data();
setTrackScreenData(TrackDatav2)
}
} getTracksData()
// SNAPSHOT USER DATA
db.collection("users").doc(currentUserUID)
.onSnapshot((doc) => {
setUserData(doc.data());
});
}, [])
console.log(trackscreenData.data)
это работает отлично, но когда я меняю консоль на
console.log(trackscreenData.data[0]
это дает мне эту ошибку
TypeError: undefined is not an object (evaluating 'trackscreenData.data[0]')
затем, когда я снова переключу консоль на
console.log(trackscreenData.data)
это работает, и когда я меняюсь, я возвращаюсь к
console.log(trackscreenData.data[0])
и сохраните изменения, которые дадут мне нужные данные
Что я делаю не так?
Ответ №1:
Короче говоря, вы пытаетесь использовать данные вашего асинхронного вызова до его готовности.
Чтобы справиться с ситуацией, когда ваши данные не закончили загрузку, вам следует использовать:
console.log(trackscreenData amp;amp; trackscreenData.data)
Основываясь на шаблонах в вашем коде, у вас есть эти строки в верхней части вашего компонента.
const { currentUserID } = useAuth(); // or similar
const [userData, setUserData] = useState();
const [trackscreenData, setTrackScreenData] = useState();
// NOTE: check for typos: "trackscreenData" !== "trackScreenData"
При первом рендеринге вашего кода trackscreenData
это undefined
произойдет потому, что вы не передали начальное состояние в useState()
метод.
const [trackscreenData, setTrackScreenData] = useState(/* initial state */);
// `trackscreenData` initially set to `null`
const [trackscreenData, getTracksData] = useState(null);
// `trackscreenData` initially set to `[]`
const [trackscreenData, getTracksData] = useState([]);
// `trackscreenData` initially set to the result of the function,
// an array containing the elements 0 through 99. The function is
// only executed once to set the first value.
// trackscreenData = [0, 1, 2, 3, ... , 97, 98, 99];
const [trackscreenData, getTracksData] = useState(() => {
Array.from({length: 100})
.map((_, i) => i);
}
Когда React выполняет ваш код, все вызовы сеттерам, возвращенные из useState
вызовов (например setTrackScreenData
), помещаются в очередь. Только после завершения выполнения вашего кода они оцениваются и запускаются любые новые рендеры.
const [count, setCount] = useState(0); // `count` is initially set to `0`
useEffect(() => {
if (count < 10) {
setCount(count 1);
}
})
console.log(count);
console.log("rendered");
// Console logs:
// > "0"
// > "rendered"
// > "1"
// > "rendered"
// > ...
// > "9"
// > "rendered"
// > "10"
// > "rendered"
Ваша выборка пользовательских данных должна выполняться в собственном useEffect
вызове и должна возвращать функцию отмены подписки:
useEffect(() => {
if (!currentUserUID) {
setUserData(null); // user not signed in
return;
}
// SNAPSHOT USER DATA
return db.collection("users") // <- note the return here
.doc(currentUserUID)
.onSnapshot((doc) => {
setUserData(doc.data());
});
}, [currentUserUID]);
useEffect(() => {
let disposed = false;
// Alleen preview
async function getTracksData() {
let TrackData = await firebase
.firestore()
.collection('TrackScreen')
.doc('LeerjarenData')
.get();
if (disposed) return; // component was removed, do nothing
if (!TrackData.exists) {
console.log('Geen data')
} else {
let TrackDatav2 = TrackData.data();
setTrackScreenData(TrackDatav2)
}
}
getTracksData()
.catch((err) => console.error(err)); // don't forget to handle errors!
return () => disposed = true; // ignore result if component disposed
}, []);
Ответ №2:
Вы указываете идентификатор документа .doc(...)
и, следовательно, получаете снимок данных в качестве ответа, который не является массивом.
Если бы вы использовали такие запросы, как .where(...)
тогда, он вернул бы снимок запроса.
Снимок запроса содержит ноль или более объектов DocumentSnapshot, представляющих результаты запроса. Документы могут быть доступны в виде массива с помощью свойства docs или перечислены с помощью метода forEach. Количество документов можно определить с помощью свойств пусто и размер.
Поэтому, если вы таким образом извлекаете только один документ, вам не нужно обращаться к документу, [0]
поскольку он не является массивом. Вы можете просто получить доступ к данным с помощью dataSnapshot.data()
Хотя я не вижу, где это trackscreenData
определено?
useEffect(() => {
// Alleen preview
async function getTracksData() {
let TrackData = await firebase
.firestore()
.collection('TrackScreen')
.doc('LeerjarenData')
.get();
if (!TrackData.exists) {
console.log('Geen data')
} else {
let TrackDatav2 = TrackData.data();
setTrackScreenData(TrackDatav2)
console.log(trackScreenData)
}
}
}, [])
Комментарии:
1. я пробовал, но это не работает для меня, в моем вопросе была неправильная консоль. теперь я изменил его
2. @SandervanMaastricht, пожалуйста, попробуйте скопировать мой код выше