无法正确更改componentDidMount中的状态

时间:2020-02-07 07:25:36

标签: reactjs firebase

我正在使用firebase在我的项目中做反应。代码如下


var storage = firebase.storage()
var storageRef = storage.ref();

export default class WallPics extends Component {
    constructor(props){
        super(props)
        this.state={
            images : []
        }
    }
    componentWillMount(){
        var imgArr=[]
        storageRef.listAll()
            .then(allPics=>{
                allPics.items.forEach(function (picRef){
                   picRef.getDownloadURL()
                    .then(function (url){
                        imgArr.push(
                            <img src={url} alt="pics" />
                        )
                    })

                })
                this.setState({
                    images : imgArr
                })  
            })
    }

    render() {
        return (
            <div>
                {this.state.images}
            </div>
        )
    }
}

在上面的代码中,我从Firebase存储中获取所有图片引用,并将图片下载URL附加到imgArr。在将所有URL附加到imgArr之后,我想更改状态。但是这里this.setState变空了imgArr。但是我想用图片下载URL的imgArr更改状态值。我现在该怎么做?

2 个答案:

答案 0 :(得分:2)

getDownloadURL是异步的吗?如果是,那么您应该等待诺言解决

尝试这样的事情?

async componentDidMount() {
   let imgArr=[]
   let allPics = await storageRef.listAll()
   let promises = []
   allPics.items.forEach((picRef) => {
       promises.push(picRef.getDownloadURL())
   })

   const urls = await Promise.all(promises);

   for(let url of urls){
      imgArr.push(<img src={url} alt="pics" />)
   }

   this.setState({images : imgArr})  
}

答案 1 :(得分:2)

根据React官方文件here,我不建议您直接将组件置于状态:

状态应包含组件的事件处理程序可能更改以触发UI更新的数据。

还明确指出,组件不应进入状态:

this.state应该只包含表示UI状态所需的最少数据量。因此,它不应包含:

反应组件:基于基础道具在render()中构建它们,并 状态。

因此,我建议您首先将fetch操作提取到一个单独的函数中以更好地阅读,并设置需要声明的网址(而不是组件)。

fetchPics = async() => {
  const allPics = await storageRef.listAll();
  const allUrls = await allPics.items.map(picRef => picRef.getDownloadURL());
  // here I use async, you might also use promise.all() 
  // as stated in @Alexandr Zavalii's answer
  this.setState({ images : allUrls })
}

componentDidMount() {
  this.fetchPics();
}

最后,在render函数中使用url渲染组件。

render() {
  return (
    <div>
      {this.state.images.map(url => <img src={url} alt="pics" />)}
    </div>
  )
}