React Hooks-在另一个函数中通过Promise设置状态变量

时间:2020-08-31 09:01:37

标签: javascript reactjs react-hooks es6-promise

我试图不将所有代码都写在同一个文件中,并提取常用功能,例如从Firebase下载图像到单独的功能/文件中。

我在React中有两个函数名为

  1. OfferCard(从Firebase存储获取图像的下载URL,以将图像提供给OfferCard组件)。

我正在尝试从getImage获取图像文件,并在getImage功能组件返回的<CardMedia />图像属性中显示该图像。

我面临的问题是OfferCard的getImage 无法获取数据并及时返回。表示状态变量setOfferImage仍为offerImagenull

在控制台中,我可以看到undefined是控制台记录值 AFTER 后,getImage控制台记录了值/。

我认为这是异步代码和承诺的问题,但不太确定如何解决这一问题。

OfferCard.js:

OfferCard

获取图片:

import getImage from '../utils/helperFunctions/getImage';

export default function OfferCard(props) {
    const classes = useStyles();
    const [offerImage, setOfferImage] = React.useState(null)

    useEffect(() => {
        if (props.image) {
            initFirebase();
            setOfferImage(getImage(props.image));
            console.log(offerImage)
        }
    }, [])

    return (

        <Link href={`/offers/${props.id}`}>
            <Card className={classes.card} >
                {offerImage ? 
                    <CardMedia
                    image={offerImage}
                /> : <CircularProgress/>
                }
           </Card>
        </Link>
    )
}

2 个答案:

答案 0 :(得分:1)

useEffect(() => {
  const fetchImg = async () => {
    const res = await getImage(props.image)
    setOfferImage(res);
    // `setOfferImage` is async 
    // `console.log(offerImage)` there will be console previous value of `offerImage`
  }
  if (props.image) {
    initFirebase();
    fetchImg()
  }
}, [props.image])

答案 1 :(得分:1)

此问题是您的getImage函数实际上是一个void函数,因为它会到达代码的末尾而没有任何返回,因为return(url)是在第二时刻执行的。 解决方案是使该函数异步,并返回Promise:

export default async function getImage(path) {
  let storage = firebase.storage();
  let pathReference = storage.ref(`${path}.png`);

  return new Promise((resolve, reject) => {
    pathReference.getDownloadURL()
      .then((url) => {
        console.log("returning", url);
        resolve(url);
      })
      .catch((error) => {
        // Handle any errors
        reject(error)
        console.log("Could not get image: ", error);
      });
  })
}

这样您就可以在useEffect中等待它。请注意,您实际上无法在useEffect(learn more)中等待,因此OfferCard.js将变为

useEffect(() => {
  const getImageAsync = async () => {
    const url = await getImage(props.image)
    if (url)
      setOfferImage(url)
    else {
      // handle error
    }
  }

  if (props.image) {
    initFirebase();
    getImageAsync();
  }
}, [])