i have a onSnapshot query in a function:
//firebaseutil.js
export async function getShorts(uid) {
const q = query(collection(db, 'shorted'), where('owner', '==', uid));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const urls = [];
querySnapshot.forEach((doc) => {
urls.push({
url: doc.data().url,
shorturl: doc.data().shorturl,
hits: doc.data().hits,
});
});
console.log(urls);
return urls;
});
}
Which correctly logs the data, and relog it if i change it on the firestore collection (as expected)
i am trying to access these data from a user dashboard this way:
//dashboard.js
import { getShorts } from '../lib/fbutils';
import { useEffect, useState } from 'react';
export default function Dashboard() {
const [myurls, setUrls] = useState([]);
useEffect(() => {
const fetchShorts = async () => {
if (user) {
const urls = await getShorts(user.uid);
setUrls(urls);
console.log(myurls);
console.log(urls);
}
};
fetchShorts();
}, []);
user.id is correctly set, but both urls and myurls are logged as undefined (i was thinking at least for a Promise pending)
what am i doing wrong? i usually use this pattern to retrieve data, but it's my first time i get data from a firestore subscription
CodePudding user response:
The onSnapshot()
does not return a promise and your getShorts()
function returns before the data is received. You can return a promise from that function as shown below:
let fetched = false;
export function getShorts(uid) {
return new Promise((resolve, reject) => {
const q = query(collection(db, 'shorted'), where('owner', '==', uid));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
const urls = querySnapstho.docs.map((d) => ({ id: d.id, ...d.data() }))
if (!fetched) {
// URLs fetched for first time, return value
fetched = true;
resolve(urls);
} else {
// URLs fetched already, an update received.
// TODO: Update in state directly
}
})
})
}
This should return all the URLs when you call the function await getShorts(user.uid);
but for the updates received later, you'll have to update them in the state directly because the promise has resolved now.