Quantcast
Viewing all articles
Browse latest Browse all 6400

How to type promises on react context with typescript

I'm learning to implement typescript in react and I'm struggling trying to implement a couple of async functions on context.

The error I'm getting is the following:

Argument of type '{ userData: null; favoriteCocktails: never[]; publishedRecipes: never[]; fetchUserData: (user: any) => PromiseConstructor; fetchFavoriteCocktails: (userData: UserData | null) => PromiseConstructor; fetchPublishedRecipes: (user: any) => PromiseConstructor; }' is not assignable to parameter of type 'ProfileContext'.  The types returned by 'fetchUserData(...)' are incompatible between these types.    Type 'PromiseConstructor' is missing the following properties from type 'Promise<void>': then, catch, finally, [Symbol.toStringTag]ts(2345)

This is my context:

import { createContext } from 'react'import {UserData , Cocktail} from '../types'interface ProfileContext {    userData: UserData | null,    favoriteCocktails: Array<Cocktail>,    publishedRecipes: Array<Cocktail>,    fetchUserData: (user: any) => Promise<void>,    fetchFavoriteCocktails: (userData: UserData | null) => Promise<void>,    fetchPublishedRecipes: (user: any) => Promise<void>,}const defaultState = {    userData: null,    favoriteCocktails: [],    publishedRecipes: [],    fetchUserData: (user: any) => Promise,    fetchFavoriteCocktails: (userData: UserData | null) => Promise,    fetchPublishedRecipes: (user: any) => Promise}const ProfileContext = createContext<ProfileContext>(defaultState)export default ProfileContext

This is my provider:

import ProfileContext from './ProfileContext'import { query, where, getDocs, collection } from 'firebase/firestore'import { db } from '../services/firebase.config'import { Cocktail, UserData } from '../types'import { useState } from 'react'export default function ProfileContextProvider ({ children }: { children: any }) {  const [userData, setUserData] = useState<UserData | null>(null)  const [favoriteCocktails, setFavoriteCocktails] = useState<Array<Cocktail>>([])  const [publishedRecipes, setPublishedRecipes] = useState<Array<Cocktail>>([])  const fetchUserData = async (user: any) => {    try {      const q = query(collection(db, 'mixrUsers'), where('email', '==', user.email))       const querySnapshot = await getDocs(q)      const result: any[] = []      querySnapshot.forEach(doc => result.push(doc.data()) )      setUserData(result[0])          } catch (err) {      console.error(err)    }  }  const fetchFavoriteCocktails = async (userData: UserData | null) => {    try {      const q = query(collection(db, 'mixrCocktails'), where('id', 'in', userData?.favoriteCocktails))         const querySnapshot = await getDocs(q)      const result: any[] = []      querySnapshot.forEach(doc => {result.push(doc.data())} )      setFavoriteCocktails(result)    } catch (err) {      console.error(err)    }  }  const fetchPublishedRecipes = async (user: any) => {    try {      console.log('fetchPublishedRecipes')      const q = query(collection(db, 'mixrCocktails'), where('publisherId', '==', user?.uid))         const querySnapshot = await getDocs(q)      const result: any[] = []      querySnapshot.forEach(doc => result.push(doc.data()) )      setPublishedRecipes(result)          } catch (err) {      console.error(err)    }  }  return (<ProfileContext.Provider value={{ userData, favoriteCocktails, publishedRecipes, fetchUserData, fetchFavoriteCocktails, fetchPublishedRecipes  }} >          {children}</ProfileContext.Provider>  )}

And I'm consuming it on different components in the following ways:

import { useEffect, useContext } from 'react'import ProfileContext from '../context/ProfileContext'import { RootTabScreenProps } from '../types'import { useAuthState } from 'react-firebase-hooks/auth'import { auth } from '../services/firebase.config'import { StyleSheet, Text, View, SafeAreaView, ScrollView, Image, TouchableOpacity } from 'react-native'import CocktailCard from '../components/home/cocktailCard/CocktailCard'import GenericAvatar from '../assets/images/genericAvatar.jpg'export default function ProfileScreen({ navigation }: RootTabScreenProps<'Profile'>) {  /* TODO - Profile context functions break */  const [user] = useAuthState(auth as any)  const {userData, favoriteCocktails, publishedRecipes, fetchUserData, fetchFavoriteCocktails, fetchPublishedRecipes} = useContext(ProfileContext)  useEffect(() => {    fetchUserData(user)    fetchPublishedRecipes(user)  }, [publishedRecipes])  useEffect(() => { if(userData) fetchFavoriteCocktails(userData) },[userData, favoriteCocktails])  /* ====================================== */  return (<SafeAreaView style={styles.container}><ScrollView><View style={styles.profileHeader}><Image style={styles.profilePicture} source={user ? { uri: user?.photoURL } : GenericAvatar}/><Text style={styles.profileName}>{user?.displayName}</Text></View>          ...
import { useContext, useEffect } from 'react'import ProfileContext from '../context/ProfileContext'import { RootTabScreenProps } from '../types'import { useAuthState } from 'react-firebase-hooks/auth'import { auth } from '../services/firebase.config'import { Text, StyleSheet, View } from 'react-native'import CocktailCard from '../components/home/cocktailCard/CocktailCard'export default function PublishedRecipesScreen({ navigation }: RootTabScreenProps<'Published recipes'>) {/* TODO - Profile context functions break */const [user] = useAuthState(auth as any)const { publishedRecipes, fetchPublishedRecipes } = useContext(ProfileContext)useEffect(() => {fetchPublishedRecipes(user)}, [])/* ====================================== */  return (<View style={styles.container}><Text style={styles.title}>Published recipes</Text><View style={styles.cardsContainer}>        {publishedRecipes.map((cocktail, i) => <CocktailCard key={i} cocktail={cocktail} navigation={navigation} />)}</View>      ...

I understand there is a conflict between the types I'm declaring on the context file, and the actual types the functions are returning. But I don't understand how should I declare them.

This functions fetch data from a DB and update a state, so they don't return anything.

I've tried fetchUserData: (user: any) => void, but I get Expression expected.ts(1109)

What's the right way to type this kind of functions?

Full code can be found here: https://github.com/coccagerman/mixr/

Thanks in advance!


Viewing all articles
Browse latest Browse all 6400

Trending Articles