我是React的新手。我想创建一个使用ID列表从Firebase调用项目数据的函数。
我使用TypeScript,React Native和Hooks。
我尝试以下代码:
const FavoritesScreen = () => {
const [favoritesData, setFavoritesData] = useState<Array<Item>>([])
useEffect(() => {
init()
}, [])
const init = async () => {
const data = await getFavorites(sortByTimeStamp)
setFavoritesData(data)
}
// ...
有人建议我在使用async / await时,将init函数的声明从useEffect挂钩中删除。到目前为止,一切正常。
getFavorites是异步声明的,因为它需要等待Firebase中的数据。
Visual Studio在setFavorites(data)中的单词data加上以下注释:
const data: Promise<Item | undefined>[]
Argument of type 'Promise<Item | undefined>[]' is not assignable to parameter of type 'SetStateAction<Item[]>'.
Type 'Promise<Item | undefined>[]' is not assignable to type 'Item[]'.
Type 'Promise<Item | undefined>' is missing the following properties from type 'Item': author, authorName, authorTitle, benefits, and 13 more.ts(2345)
对于我来说,这个问题是应允还是不确定的,也不清楚如何解决。
以下是完整的代码,如果有帮助的话:
import React, { useEffect, useState, useContext } from 'react'
import { Text, SafeAreaView, StyleSheet } from 'react-native'
import colors from '../constants/colors'
import { FirebaseContext, FavoritesContext } from 'src/firebase'
import { Item } from '../types/item'
import { Timestamp } from '@firebase/firestore-types'
type CompareFunction = (a: [string, Timestamp], b: [string, Timestamp]) => number
const FavoritesScreen = () => {
const { firebase } = useContext(FirebaseContext)
const { favorites } = useContext(FavoritesContext)
const [favoritesData, setFavoritesData] = useState<Array<Item>>([])
useEffect(() => {
init()
}, [])
const init = async () => {
// call the functions used in useEffect
const data = await getFavorites(sortByTimeStamp)
setFavoritesData(data)
}
// This function gets Firestore data for one id
const getItemDataFromId = async (id: string) => {
try {
const data: Item = await firebase.db.collection('content').doc(id).get().data()
return data
} catch (error) {
console.log(`Could not get Firebase data from Id: ${id}. Error message: ${error}`)
}
}
// this function compare the timestamps for use in the Array.prototype.sort() method.
function sortByTimeStamp(a: [string, Timestamp], b: [string, Timestamp]) {
let am = 1
let bm = 1
try {
const am = a[1].toMillis()
} catch {
return -1
}
try {
const bm = b[1].toMillis()
} catch {
return 1
}
return am - bm
}
// Create an array of items data from the favorites object, sorted ny timestamp
const getFavorites = async (compareFunction?: CompareFunction) => {
// Convert the object to a [[key1, value1],[key2,value2],...) array
const favoritesArray = Object.entries(favorites)
// sort if needed
compareFunction && favoritesArray.sort(compareFunction)
// get the data from firebase
const items = favoritesArray.map(async ([key, value]) => await getItemDataFromId(key))
return items
}
return (
<SafeAreaView style={styles.container}>
<Text>Work in progress</Text>
</SafeAreaView>
)
}
//// Styles ////
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background,
justifyContent: 'center',
alignItems: 'center',
},
})
export default FavoritesScreen
答案 0 :(得分:1)
您可能遇到的第一个问题是在map
函数中处理异步项目。这将返回解析为Item
的诺言数组,而不是Item
元素的数组。
一个简单的解决方法是将其包装在Promise.all
中。
const items = favoritesArray.map(async ([key, value]) => await getItemDataFromId(key));
return Promise.all(items);
但是,在此之后,您可能会遇到返回类型为Array<Item | undefined>
而不是Array<Item>
的问题。有几种方法可以解决此问题。 items
值可以强制转换为Item[]
,但最好过滤掉未定义的值。为此,我建议您查看at this question。例如:
items.filter((x): x is Item => x !== undefined);