如何同步使用FileReader'在react / redux中

时间:2017-03-05 01:05:09

标签: javascript reactjs redux filereader

由于它的异步特性,我在设计一个在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的最佳方法。

1 个答案:

答案 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;
  });
};