'Promise<Item | undefined>[]' 类型的参数不可分配给 'SetStateAction<Item[]>' 类型的参数

Argument of type 'Promise<Item | undefined>[]' is not assignable to parameter of type 'SetStateAction<Item[]>'

我对 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)

我不清楚问题是 promise 还是 undefined,也不清楚如何解决。

如果对您有帮助,请查看完整代码:

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

您可能 运行 遇到的第一个问题是在 map 函数中处理异步项目。这是 return 解析为 Item 的承诺数组,而不是 Item 元素数组。

一个简单的解决方法是将其包装在 Promise.all.

const items = favoritesArray.map(async ([key, value]) => await getItemDataFromId(key));
return Promise.all(items);

但是,在此之后,您可能会 运行 遇到 return 类型 Array<Item | undefined> 而不仅仅是 Array<Item> 的问题。有几种方法可以解决这个问题。 items 值可以转换为 Item[],但最好过滤掉未定义的值。为此,我建议查看 。例如:

items.filter((x): x is Item => x !== undefined);