首页 > 解决方案 > 反应 useEffect 没有正确更新状态

问题描述

我正在尝试通过在组件安装时执行异步操作来更新状态。我在images道具中有一个图像ID列表,开始时组件应该遍历每个ID并获取Firebase存储中图像的实际URL。然而,包含 url 的数组一次只能获得一个 url,尽管有许多 id 通过 images 属性传递给它。我究竟做错了什么?

import React, { useEffect, useState } from 'react';
import { Panel, Carousel, Divider } from 'rsuite';
import { storage } from '../../misc/firebase';

const ListingItem = ({ title, images, owner, props }) => {
  const [imageUrls, setImageUrls] = useState([]);

  useEffect(() => {
    for (const img in images) {
      storage
        .ref(`listings/${owner}/images`)
        .child(images[img])
        .getDownloadURL()
        .then(url => setImageUrls([...imageUrls, url])); // this should append the url to imageUrls
    }
  }, []);

  return (
    <Panel
      {...props}
      shaded
      bordered
      bodyFill
      style={{ display: 'inline-block', height: '100' }}
    >
      <Carousel>
        { /* This only ever outputs a single image */ }
        {imageUrls.length !== 0 &&
          imageUrls.map((img, idx) => <img src={img} key={idx} />)}
      </Carousel>
      <Panel header={title}>
        <small>foo</small>
      </Panel>
    </Panel>
  );
};

export default ListingItem;

标签: reactjsfirebaseasync-awaitreact-hooksfirebase-storage

解决方案


回调仅在useEffect挂载时运行一次。在挂载时,imageUrls状态变量被初始化为空数组。结果,在useEffect回调内部,这是:

.then(url => setImageUrls([...imageUrls, url]));

将始终等同于:

.then(url => setImageUrls([, url]));

因为初始数组是空的。

请改用回调形式,以便根据当前状态设置新状态,而不是根据旧(现在可能已过时)闭包中的变量:

.then(url => setImageUrls(currentImageUrls => [...currentImageUrls, url]));

推荐阅读