我有下面的文件选择器对话框。我希望允许选择多个文件。选定文件后,我要呈现所选文件的预览。我的代码是:
<input
type="file"
multiple
accept=".png, .jpeg"
onChange={e => {
this.setState({ previews: [] });
if (!e.target.files) {
return;
}
var previews = [];
for (var i = 0; i < e.target.files.length; i++) {
var file = e.target.files[i];
(function(file, previews) {
var reader = new FileReader();
reader.onload = function(e) {
// console.log(e.target.result);
console.log("Just pushed a new preview");
previews.push(e.target.result);
};
reader.readAsDataURL(file);
})(file, previews);
}
console.log("All files read");
// I want this to be called only after
// all the file contents are read
this.setState({ previews });
}}
/>但是,使用上面的代码,我的Just pushed a new preview是在控制台上打印All files read之后打印出来的。
有什么方法可以让FileReader循环(闭包)完成,然后调用this.setState({previews})吗?
如果重要的话,所有这些代码都在一个react文件中。
发布于 2017-09-21 10:12:24
您需要在setState事件中移动onLoad。由于文件读取器是异步的,所以onLoad之外的设置状态将在事件完成之前触发它,并将导致空的或不完整的previews数组。
var previews = [];
var s = this;
for (var i = 0; i < e.target.files.length; i++) {
var file = e.target.files[i];
var reader = new FileReader();
reader.onload = function(e) {
previews.push(e.target.result);
s.setState({ previews });
};
reader.readAsDataURL(file);
}发布于 2017-09-21 15:48:18
使用Promise.all等待完成所有承诺,以知道是否处理了所有文件。而且,您需要在读取完文件后立即更新状态。最好添加一个进度条和setState来更新它。
var Sample = React.createClass({
getInitialState: function () { return { previews: [], allfilesdone:false }; },
render: function() {
var p = this.state.previews.map((p) => <div>{p}</div>);
return (
<div style = {this.styler}>
<input id="upload" multiple
accept=".txt" type="file"
onClick={(e) => this.setState({allfilesdone: false})}
onChange={(event)=> {
var s = this;
this.setState({previews:[], allfilesdone: false});
var fs = event.target.files;
Promise.all([...fs].map((file) => {
var reader = new FileReader();
return new Promise((resolve,reject) => {
reader.onload = (ev) => {
resolve(ev.target.result);
var pt = this.state.previews;
pt.push(ev.target.result);
s.setState({previews: pt});
}
reader.readAsText(file);
});
}))
.then(ft => {
this.setState({allfilesdone: true});
});
}}/>
<div>all processed: {this.state.allfilesdone?"true":"false"}</div>
<div>number of files: {this.state.previews.length}</div>
<div>{p}</div>
</div>
);
}
});
React.render(
<Sample />,
document.getElementById('mount-point'));https://stackoverflow.com/questions/46340315
复制相似问题