为什么使用 FileReader 读取文件内容时 setState 不起作用?
Why is setState not working when using FileReader to read file content?
我正在将一个文件输入 select 多个可以预先可视化的图像。
为了处理多个图像,我将它们放在组件状态的数组中,并映射预可视化图像。
但是当我 select 输入图像并使用 this.setState({imgArray: newArray})
设置状态时,this.state.array.map(image=><img src={image}/>)
不会重新渲染 selected 图像。
代码:
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
}
}
渲染:
<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 异步读取文件内容。
由于这种异步性质,状态正在设置,即 this.setState({fotos: newArray})
在 数据 url 设置在 newArray
之前,即 newArray.push(event.target.result)
。
这就是您选择的文件没有显示的原因。
要修复它,您可以使用创建 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)
})
}
This has some good examples of Promises and their executing orders. Also check this 关于使用 FileReader 和 Promise.
我正在将一个文件输入 select 多个可以预先可视化的图像。
为了处理多个图像,我将它们放在组件状态的数组中,并映射预可视化图像。
但是当我 select 输入图像并使用 this.setState({imgArray: newArray})
设置状态时,this.state.array.map(image=><img src={image}/>)
不会重新渲染 selected 图像。
代码:
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
}
}
渲染:
<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 异步读取文件内容。
由于这种异步性质,状态正在设置,即 this.setState({fotos: newArray})
在 数据 url 设置在 newArray
之前,即 newArray.push(event.target.result)
。
这就是您选择的文件没有显示的原因。
要修复它,您可以使用创建 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)
})
}
This has some good examples of Promises and their executing orders. Also check this 关于使用 FileReader 和 Promise.