Hello
I am building an online recipe book using ionic react and firebase as backend. A user has to be able to add a recipe to his favorites.
In firebase i have a collecion ‘users’. Every user has an array field ‘favoriterecipes’ containing the id’s of all the recipes he/she has favorited.
I have an interface Auth wich describes the user collection in firebase. Whenever a user is logged in, his data is added to a global state.
When i press the ‘favorite’ button on a recipe, the id of the recipe gets added to the favorite recipes array in firebase. Then when i go back to the page that shows the user all his recipes that are favorited, i first have to reload the page before it adds the newly favorited recipe. I think it is cause the function read(id) uses .get() and i should use .onSnapshot to add a listener. I added the function read2(id) to try this out. When i use read2 it gives an error ‘: Property ‘username’ does not exist on type ‘void’.’
(same for favoriterecipes and badges) in the useAuthInit function under 'setAuthInit({…}
Is this indeed the problem? if yes: anyone knows how i can fix the error? If not: anyone knows how to fix this?
Code for auth:
export function useAuthInit(): AuthInit {
const [authInit, setAuthInit] = useState<AuthInit>({loading: true});
useEffect(() => {
return firebaseAuth.onAuthStateChanged((firebaseUser) => {
if(firebaseUser){
read2(firebaseUser.uid).then((user) => {
console.log("user: ",user);
setAuthInit({
loading: false,
auth: {
loggedIn: true,
userId: firebaseUser.uid,
userName: user.username,
favoriteRecipes: user.favoriteRecipes,
badges: user.badges
}});
})
} else {
setAuthInit({loading: false, auth: {loggedIn: false}})
}
});
}, []);
return authInit;
}
async function read(id) {
let response = await db
.collection("users")
.doc(id)
.get();
if (response === null || response === undefined) return null;
return response.data();
}
async function read2(id) {
db
.collection("users")
.doc(id)
.onSnapshot((doc) => {
if (doc !== null || doc !== undefined) {
return doc.data();
}
});
}
Code for all the user his favorited recipes:
import {
IonCard,
IonCardContent,
IonCardHeader,
IonCardSubtitle,
IonCardTitle,
IonContent,
IonHeader,
IonPage,
IonTitle,
} from '@ionic/react';
import { db } from '../firebase/firebase.utils';
import React, {useEffect, useState} from "react";
import {Recipe, toRecipe} from "../models/recipe";
import Header from "../components/Header";
import {useAuth} from "../auth";
const Favorites: React.FC = () => {
const { userId, favoriteRecipes } = useAuth();
const [recipes, setRecipes] = useState<Recipe[]>([]);
useEffect(() => {
const recipesRef = db.collection('recipes');
favoriteRecipes.forEach( el => {
let recipeRef = recipesRef.doc(el);
recipeRef.onSnapshot ((doc) => {
setRecipes(arr => [...arr, toRecipe(doc)]);
});
})
}, [userId, favoriteRecipes]);
return (
<IonPage>
<IonHeader>
<Header />
</IonHeader>
<IonContent fullscreen>
<IonTitle className="ion-padding">Favoriete Recepten</IonTitle>
{recipes.map((entry, index) =>
<IonCard routerLink={`/my/recipes/view/${entry.id}`} key={index}>
<img src={entry.photo} alt={entry.title}/>
<IonCardHeader>
<IonCardSubtitle>{entry.userName}</IonCardSubtitle>
<IonCardTitle>{entry.title}</IonCardTitle>
</IonCardHeader>
<IonCardContent>{entry.description}</IonCardContent>
</IonCard>)}
</IonContent>
</IonPage>
);
};
export default Favorites;
1 post - 1 participant