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

Mar*_*tty 2 javascript render setstate reactjs

我正在创建一个文件输入来选择可以预先可视化的多个图像。

为了处理多个图像,我将它们放入组件状态的数组中,并映射预可视化图像。

但是,当我从输入中选择图像并使用 设置状态时this.setState({imgArray: newArray})this.state.array.map(image=><img src={image}/>)不会重新渲染所选图像。

代码:

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
  }
}
Run Code Online (Sandbox Code Playgroud)

使成为:

<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>
Run Code Online (Sandbox Code Playgroud)

Aje*_*hah 5

FileReader异步读取文件内容。

由于这种异步特性,在 ie 中设置数据 urlthis.setState({fotos: newArray})之前会先设置状态ie 。newArraynewArray.push(event.target.result)

这就是您选择的文件没有显示的原因。

要修复它,您可以使用 create Promise,它会在每个文件的事件发生后得到解决load。并使用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)
    })
}
Run Code Online (Sandbox Code Playgroud)

这里有一些Promise 及其执行命令的好例子。另请检查有关将FileReaderPromise一起使用的信息。