简体   繁体   English

为什么使用 FileReader 读取文件内容时 setState 不起作用?

[英]Why is setState not working when using FileReader to read file content?

I'm making a file input to select multiple images that can be pre-visualized.我正在将文件输入到 select 多个可以预可视化的图像。

To handle multiple images I put them in an array of the component's state, and map the pre-visualized images.为了处理多个图像,我将它们放在组件的 state 和 map 预可视化图像的数组中。

But when I select the images from the input and set the state with this.setState({imgArray: newArray}) , this.state.array.map(image=><img src={image}/>) doesn't re-render the selected images.但是当我 select 输入图像并使用this.setState({imgArray: newArray})设置 state 时, this.state.array.map(image=><img src={image}/>)没有。 - 渲染选定的图像。

Code:代码:

export default class posts extends Component {
  state = {
    fotos: ["/iconos/img.svg"] // If there are not img selected, it renders one image icon
  }

  onUploadVarious = e => {
    let newArray = []
    Object.values(e.target.files).map(file => {
      let nuevo = new FileReader()
      nuevo.onload = event=> newArray.push(event.target.result)
      nuevo.readAsDataURL(file)}
    )
    this.setState({fotos: newArray}) // the state is set correctly
  }
}

Render:使成为:

<div className=" border rounded" style={{"height":"30%", "overflow":"auto"}}>
    {this.state.fotos.map(foto =>
      <img src={foto||"/iconos/img.svg"}
        id="arch-preview"/>)} // it doesn't re-render when fotos state is changed
</div>

// input
<div className="mt-auto">
    <input multiple="multiple" type="file" 
    onChange={this.onUploadVarious} 
    className="form-control-file" name="file" />
</div>

FileReader reads file content asynchronously . FileReader异步读取文件内容。

Due to this asynchronous nature, state is being set ie this.setState({fotos: newArray}) before data urls are set in newArray ie newArray.push(event.target.result) .由于这种异步特性,state 被设置,即this.setState({fotos: newArray})数据 url被设置在newArraynewArray.push(event.target.result)之前。

And that's the reason your selected files aren't showing up .这就是您选择的文件没有显示的原因。

To fix it, you can use create Promise which gets resolved after load event of each file.要修复它,您可以使用创建Promise来解决每个文件的load事件。 And use Promise.all which would be resolved after each Promise has resolved and then use setState :并使用Promise.all将在每个 Promise 解决后解决,然后使用setState

readAsDataURL = (file) => {
  return new Promise((resolve, reject) => {
    const fr = new FileReader()
    fr.onerror = reject
    fr.onload = function () {
      resolve(fr.result)
    }
    fr.readAsDataURL(file)
  })
}

onUploadVarious = (e) => {
  Promise.all(Array.from(e.target.files).map(this.readAsDataURL))
    .then((urls) => {
      this.setState({ fotos: urls })
    })
    .catch((error) => {
      console.error(error)
    })
}

This has some good examples of Promises and their executing orders . 有一些Promises 及其执行命令的好例子。 Also check this about using FileReader with Promise .另请检查有关FileReaderPromise一起使用的信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM