由于它的异步特性,我在设计一个在react / redux应用程序中使用FileReader API的解决方案时遇到了一些麻烦。我做了一些环顾四周,但没有任何对我有用。
我有一个react组件,它使用react-dropzone来获取文件的内容并在以后处理它的内容。每当使用dropzone删除文件时,都会触发回调:
onGuestListDrop = (fileData) => {
const headers =
FileParser.read(fileData)
.getHeaders();
};
我的内部API设计的目的是获取.csv或.xlsx文件的标头,以便将列名映射到现有的系统字段名。我解析文件的内容没有任何问题,我得到了它的工作,问题在于FileReader.onload事件。
我的顶级文件解析器是:
class FileParser {
constructor(file) {
this.reader = new FileReader();
this.init(file[0]);
return this;
}
static read(file) {
return new FileParser(file);
}
init(file) {
switch (file.type) {
case 'text/csv':
this.parser = new CsvParser(this.reader, file);
break;
default:
this.parser = new XlsParser(this.reader, file);
break;
}
}
getHeaders() {
return this.parser.getHeaders();
}
}
CSV类是:
class CsvParser {
constructor(reader, file) {
this.reader = reader;
this.file = file;
this.parse();
return this;
}
parse() {
this.reader.readAsText(this.file, "UTF-8");
this.reader.onload = function (evt) {
const { result } = evt.target;
this.parsedContent = Papa.parse(result);
console.log(this.parsedContent);
};
}
getHeaders() {
return this.parsedContent.data[0];
}
}
现在的问题是,当我尝试通过getHeaders方法访问标头时,我未定义,因为FileReader工作异步。有没有办法通过一些重构来完成这项工作,或者这是不可能的?
我在考虑使用redux操作,但我不确定如何将解析器类与存储连接起来。我想过将一个动作直接传递给解析器类,这样我就可以在FileReader.onload事件中激活动作创建者。我认为这可行,但我不确定这是在情况下使用redux的最佳方法。
答案 0 :(得分:1)
在您的CsvParser
中添加延迟模式。
class CsvParser {
constructor(reader, file) {
this.reader = reader;
this.file = file;
this.deferred = {};
let promise = new Promise((resolve, reject) => {
this.deferred.resolve = resolve;
this.deferred.reject = reject;
});
this.deferred.promise = promise;
this.parse();
return this;
}
parse() {
this.reader.readAsText(this.file, "UTF-8");
this.reader.onload = function (evt) {
const { result } = evt.target;
this.parsedContent = Papa.parse(result);
console.log(this.parsedContent);
this.deferred.resolve(this.parsedContent.data[0])
};
}
getHeaders() {
return this.deferred.promise;
}
现在更改您的onGuestListDrop
方法
onGuestListDrop = (fileData) => {
let headers = {};
FileParser.read(fileData).getHeaders().then(function (headers) {
headers = headers;
});
};