I am creating a twitter clone using firebase with rtkquery. I haven't really seen anyone using rtkquery with firebase and i had to use a promise to resolve the data otherwise i was not getting the data
return new Promise((resolve, reject) => {
onSnapshot(q,(querySnapshot)=>{
tweetsArr=querySnapshot.docs.map((doc)=>{
console.log(doc.data());
return {id:doc.id,
...doc.data()}
})
console.log(tweetsArr);
resolve({data:tweetsArr});
})})
I use this function in my apiSlice to get the posts for the index page. The problem is if i navigate to the profile page and refresh it and then navigate back to the index page i get the data of the profile page (getRetweetedPosts()) on the index page rather than the (getPosts()). I consoled.log() and checked and i seem to be going in the right function in api slice (getPosts()) but it is resolving to the previous data of the profile page (getRetweetedPosts()) which is then displayed on the index page and then the righ data is resolved which i know because i am using console.log for everything but it is not displayed only when i refresh the page is it displayed.
apiSlice getPosts
export const apiSlice = createApi({
reducerPath:'api/apiSlice',
baseQuery: fakeBaseQuery(),
// The "endpoints" represent operations and requests for this server
tagTypes: ['Posts','Users','RetweetPosts'],
endpoints: builder => ({
getPosts: builder.query<Posts[],void>({
async queryFn(currUserId):Promise<any>{
try{
let currUserDocRef = doc(db,`users/${currUserId}`);
let docData=(await getDoc(currUserDocRef)).data();
//console.log(docData);
let followingsArr=docData?.following??[];
followingsArr.push(currUserId);
//console.log(followingsArr);
let tweetsArr: { }[]=[];
const q=query(collection(db,'tweets'), where("creatorId", "in" , followingsArr))
return new Promise((resolve, reject) => {
onSnapshot(q,(querySnapshot)=>{
tweetsArr=querySnapshot.docs.map((doc)=>{
// console.log(doc.data());
return {id:doc.id,
...doc.data()}
})
// console.log(tweetsArr);
resolve({data:tweetsArr});
})})
}
catch(err:any){
return{error:err}
}
},providesTags: ['Posts']})
getRetweetedPosts
getRetweetedPosts: builder.query<Posts[],void>({
async queryFn(currUserId):Promise<any>{
try{
let tweetsArr: { }[]=[];
const q=query(collection(db,'tweets'), where("retweetedBy", "array-contains" , currUserId))
return new Promise((resolve, reject) => {
onSnapshot(q,(querySnapshot)=>{
tweetsArr=querySnapshot.docs.map((doc)=>{
//console.log(doc.data());
return {id:doc.id,
...doc.data()}
})
//console.log(tweetsArr);
resolve({data:tweetsArr});
})})
}
catch(err:any){
return{error:err}
}
},providesTags: ['RetweetPosts']}),
CodePudding user response:
onSnapshot
is the wrong tool here. onSnapshot
will not be called once, but it will keep running and re-execute again and again every time you get new data. Your queryFn
on the other hand will only run once - and also the Promise you create there can only resolve once. That means you do create a memory leak (data will hang around forever since the onSnapshot
listener will not unsubscribe) with no benefit.
You probably should use something that gets that data once from firebase instead - like getDoc
. That will also be easier to use.
async queryFn(currUserId) {
try{
let tweetsArr: { }[]=[];
const q=query(collection(db,'tweets'), where("retweetedBy", "array-contains" , currUserId))
const querySnapshot = await getDocs(q)
const data = querySnapshot.docs.map((doc)=> ({id: doc.id, ...doc.data()}))
return { data }
catch(err:any){
return{error:err}
}