首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RefluxJS“单间”商店?

RefluxJS“单间”商店?
EN

Stack Overflow用户
提问于 2015-10-05 22:57:55
回答 1查看 407关注 0票数 2

好吧..。我创建了一个上传组件,当用户上传图像时,该组件使用FileReader API显示图像预览。

但是,如果我在另一个组件中使用了3个组件,当我上传一个图像时,这个图像也会在3个组件中重复。

示例:

代码语言:javascript
复制
... in render method
<UploadImage />
<UploadImage />
<UploadImage />
.... 

我的组成部分:

代码语言:javascript
复制
var React = require('react');
var Reflux = require('reflux');

// Actions
var actions = require('../../actions/Actions');

// Stores
var UploadStore = require('../../stores/ui/UploadStore');

var UI = require('material-ui');
var FlatButton = UI.FlatButton;
var Snackbar = UI.Snackbar;

var UploadImage = React.createClass({

  mixins: [Reflux.connect(UploadStore, 'upload')],

  propTypes: {
    filename: React.PropTypes.string,
    filesrc: React.PropTypes.string,
    extensions: React.PropTypes.array.isRequired
  },

  getDefaultProps: function() {
    return {
      extensions: ['jpg', 'png', 'jpeg', 'gif']
    };
  },

  _uploadImage: function () {
    var file = {
      file: this.refs.upload.getDOMNode().files[0] || false,
      extensions: this.props.extensions
    };

    try {
      actions.upload(file);
    }
    catch (e) {
      console.log(e);
    }
  },


  _uploadedImage: function() {
    if (this.state.upload.filename) {
      return (
        <div className="upload-image">
          <img src={this.state.upload.filesrc} />
          <p>{this.state.upload.filename}</p>
        </div>
      );
    }
  },

  render: function() {

    return (
      <div className="upload-image-container component-container">
        <div className="upload-fields component-fields">
          <h3>Imagem</h3>
          <p>Arquivos PNG ou SVG no tamanho de XXXxYYYpx de até 50kb.</p>

          <FlatButton label="Selecionar Imagem" className="upload-button">
            <input
              type="file"
              id="imageButton"
              className="upload-input"
              ref="upload"
              onChange={this._uploadImage} />
          </FlatButton>
        </div>

        {this._uploadedImage()}
      </div>
    );
  }
});

module.exports = UploadImage;

我的店:

代码语言:javascript
复制
var Reflux = require('reflux');

var actions = require('../../actions/Actions');

var UploadStore = Reflux.createStore({

  listenables: [actions],

  data: {
    filename: '',
    filesrc: ''
  },

  getInitialState: function() {
    return this.data;
  },

  onUpload: function (f) {
    if (f) {
      // Check extension
      var extsAllowed = f.extensions;

      if (this.checkExtension(extsAllowed, f.file.name)) {

        // Crate the FileReader for upload
        var reader = new FileReader();
        reader.readAsDataURL(f.file);

        reader.addEventListener('loadend', function() {
          this.setData({
            uploaded: true,
            filename: f.file.name,
            filesrc: reader.result
          });
        }.bind(this));

        reader.addEventListener('error', function () {
          actions.error('Não foi possível ler o seu arquivo. Por favor, verifique se enviou o arquivo corretamente.');
        }.bind(this));
      }
      else {
        actions.error('O arquivo que você está tentando enviar não é válido. Envie um arquivo nas seguintes extensões: ' + extsAllowed.join(', ') + '.');
      }
    }
    else {
      actions.error('File object not found.');
    }
  },

  checkExtension: function (extensions, filename) {
    var fileExt = filename.split('.').pop().toLowerCase();
    var isSuccess = extensions.indexOf(fileExt) > -1;

    if (isSuccess) return true;

    return false;
  },

  setData: function(data) {
    this.data = data;

    this.trigger(data);
  }

});

module.exports = UploadStore;

结果:

有什么想法吗?

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-05 23:30:19

不幸的是,商店的行为就像一个单例,即只有一个UploadStore实例。

您可以做的是引入一个额外的参数,以保持上传分开。您的商店现在将接受一个上载数组,但是每个上传都会被标记为类别,您的组件也将有一个类别,并且只从存储区获取属于同一类别的图像。这是使用Reflux.connectFilter混合器完成的。

首先,我将上传的图像分离到它自己的组件中,如下所示:

代码语言:javascript
复制
var UploadedImage = React.createClass({
  propTypes: {
    upload: React.PropTypes.object.isRequired
  },

  render: function() {
      return (
        <div className="upload-image">
          <img src={this.props.upload.filesrc} />
          <p>{this.props.upload.filename}</p>
        </div>
      );
  }
});

然后,我们必须更改UploadImage组件中的一些内容,以便它将按类别进行筛选:

代码语言:javascript
复制
var UploadImage = React.createClass({

  // only select those uploads which belong to us
  mixins: [
    Reflux.connectFilter(UploadStore, "uploads", function(uploads) {
        return uploads.filter(function(upload) {
           return upload.category === this.props.category;
        }.bind(this))[0];
    })
  ],

  propTypes: {
    filename: React.PropTypes.string,
    filesrc: React.PropTypes.string,
    extensions: React.PropTypes.array.isRequired,
    // an additional prop for the category
    category: React.PropTypes.string.isRequired
  },

  _uploadImage: function () {
    var file = {
      file: this.refs.upload.getDOMNode().files[0] || false,
      extensions: this.props.extensions
    };

    try {
      // pass in additional parameter!
      actions.upload(file, this.props.category);
    }
    catch (e) {
      console.log(e);
    }
  },

  render: function() {
    return (
      <div className="upload-image-container component-container">
        <div className="upload-fields component-fields">
          <h3>Imagem</h3>
          <p>Arquivos PNG ou SVG no tamanho de XXXxYYYpx de até 50kb.</p>

          <FlatButton label="Selecionar Imagem" className="upload-button">
            <input
              type="file"
              id="imageButton"
              className="upload-input"
              ref="upload"
              onChange={this._uploadImage} />
          </FlatButton>
        </div>

        {this.state.uploads.map(function(upload, index) {
           return <UploadedImage key={index} upload={upload}/>;
        })}
      </div>
    );
  }
});

您的商店现在保存了一个"file“对象数组,每个对象都有一个类别标记:

代码语言:javascript
复制
var UploadStore = Reflux.createStore({

  listenables: [actions],

  // data is now an array of objects
  data: [],

  getInitialState: function() {
    return this.data;
  },

  // here we get the file + category
  onUpload: function (f, category) {
    if (f) {
      // Check extension
      var extsAllowed = f.extensions;

      if (this.checkExtension(extsAllowed, f.file.name)) {

        // Crate the FileReader for upload
        var reader = new FileReader();
        reader.readAsDataURL(f.file);

        reader.addEventListener('loadend', function() {
          this.setData(this.data.concat([{
            uploaded: true,
            filename: f.file.name,
            filesrc: reader.result,
            category: category /* adding category here */
          }]));
        }.bind(this));

        reader.addEventListener('error', function () {
          actions.error('Não foi possível ler o seu arquivo. Por favor, verifique se enviou o arquivo corretamente.');
        }.bind(this));
      }
      else {
        actions.error('O arquivo que você está tentando enviar não é válido. Envie um arquivo nas seguintes extensões: ' + extsAllowed.join(', ') + '.');
      }
    }
    else {
      actions.error('File object not found.');
    }
  },

  checkExtension: function (extensions, filename) {
    var fileExt = filename.split('.').pop().toLowerCase();
    var isSuccess = extensions.indexOf(fileExt) > -1;

    if (isSuccess) return true;

    return false;
  },

  setData: function(data) {
    this.data = data;

    this.trigger(data);
  }

});

最后,在您的视图中,您可以像这样使用UploadImage组件:

我临时编写了代码,所以可能会有一些问题--但更多的是关于这个概念。另外,现在每个类别可以上传多个图像,如果不想这样做,那么考虑用散列映射替换存储中的数组,这样键与类别对应--那么每个类别只能上传一个图像。

回复您的评论

也许你可以用一种工厂的方法来解决商店的问题,比如:

代码语言:javascript
复制
var UploadStoreFactory = function() {
  return Reflux.createStore({
    /* your existing code as it was originally */
  });
};

var UploadImage = React.createClass({ 
  mixins: [Reflux.connect(UploadStoreFactory(), 'upload')],

  /* your existing code as it was originally */
});

但我怀疑你的行为会触发你的上传商店的所有实例,但值得一试。但是这也带来了很多缺点,如其他组件也不能轻易听这个商店的话。

this堆栈溢出中,提出了一个类似的问题,而且在概念上正确的方法是为所有人使用一个桶/存储,并在存储中保留标记的项,以便将它们分开。

请记住,商店也会被清除,例如,如果您创建了一个包含产品和不同类别的网络商店,那么每次用户切换到另一个类别时,您都会清除并重新填充ProductStore。如果您另外有一个侧栏,它可能显示“您可能喜欢的产品”,那么我会将其建模为一个单独的存储区,即ProductSuggestionStore,但都包含"Products“类型的对象。

如果存储在语义上不同,但共享大量的上载逻辑,则还可以尝试为您的商店构建一个基本原型/类,然后将特定存储扩展或将上载逻辑外包到服务类中。

如果您担心性能问题,即一次上传会导致所有组件重新呈现,那么您可以在shouldComponentUpdate中添加一个检查。

一个很好的例子,为什么只使用一个商店可能是这样的情况,用户想关闭窗口,但在您的网站上的某个地方,一个上传仍然挂起,然后您的主要应用程序视图只需检查一个商店。而且,上传可以很容易地排队,这样带宽就不会耗尽,因为所有的上传都要经过一个商店。

另外,请记住,您可以有可以收听其他商店的商店,例如,UploadHistoryStore保存了最后10次上传的时间戳记录。所有上传都进入同一个桶,但如果有“最后10个上传”组件,则只需听"UploadHistoryStore“即可。

代码语言:javascript
复制
var UploadStore = Reflux.createStore({
    /* ... upload stuff and trigger as usual ... */
});


var UploadHistoryStore = Reflux.createStore({
    // keep the last ten uploads
    historyLength: 10,

    init: function() {
        // Register statusStore's changes
        this.listenTo(UploadStore, this.output);
        this.history = [];
    },

   // Callback
    output: function(upload) {
        this.history.push({
            date: new Date(),  // add a date when it was uploaded
            upload: upload     // the upload object
        }).slice(1, this.historyLength);

        // Pass the data on to listeners
        this.trigger(this.history);
    }
});
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32959193

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档