RefluxJS negozio "single"?

voti
2

Beh .. ho creato un componente di upload, quando l'utente caricare un'immagine componente mostrare un'immagine di anteprima utilizzando FileReader API.

Ma, se ho usato 3 componenti in un altro componente, quando si invia un'immagine, questa immagine si ripete anche in 3 componenti.

Esempio:

... in render method
<UploadImage />
<UploadImage />
<UploadImage />
.... 

La mia componente:

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;

Il mio negozio:

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;

Il risultato:

negozio

Qualche idea?

Grazie!

È pubblicato 05/10/2015 alle 22:57
fonte dall'utente
In altre lingue...                            


1 risposte

voti
3

purtroppo il negozio si comporta come un Singleton, cioè v'è una sola istanza UploadStore.

Che cosa si può fare è introdurre un parametro in più per mantenere i caricamenti a parte. Il tuo negozio sarà ora prendere una serie di arrivi, ma ogni upload è etichettato con la categoria e il componente avrà anche una categoria e prende solo le immagini dal negozio che appartengono alla stessa categoria. Questo viene fatto usando il Reflux.connectFiltermixin.

In primo luogo, mi piacerebbe separare l'immagine caricata nella propria componente in questo modo:

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

Poi dobbiamo cambiare alcune cose all'interno del vostro UploadImagecomponente in modo che possa filtrare per categoria:

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

E il tuo negozio detiene ora un array di oggetti "file", ognuna con i tag una categoria:

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

});

E, infine, a suo avviso è possibile utilizzare il UploadImagecomponente in questo modo:

Ho scritto il codice al volo, quindi ci potrebbero essere alcuni problemi - ma è di più sul concetto. Inoltre è possibile caricare più di un'immagine per categoria ora, se questo non è desiderato, quindi pensare di sostituire la matrice nel negozio con una mappa di hash, in modo che i tasti corrispondono alla categoria - allora una sola immagine può essere caricato in ogni categoria.

Risposta al tuo commento

Forse si potrebbe ottenere via con un metodo factory per il negozio, vale a dire qualcosa di simile:

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 */
});

ma ho il sospetto che la vostra azione attiverà tutte le istanze di vostri negozi di upload, ma vale la pena di provare. Ma questo viene fornito con un sacco di svantaggio, come gli altri componenti non possono ascoltare questo negozio facilmente.

In questo StackOverflow viene posta una domanda simile, e anche il modo concettuale giusto per farlo è quello di utilizzare un secchio / store per tutti e mantenere gli elementi in negozio etichettato in modo da poter tenerli separati.

Tenete a mente che i negozi anche ottenere cancellato un ricaricate, ad esempio se si crea un web-negozio con i prodotti e le diverse categorie, è chiaro e riempire ProductStorel'ogni volta l'utente passa a un'altra categoria. Se si dispone inoltre di una barra laterale che forse mostra "I prodotti potrebbero piacerti" allora io modellare questo come un archivio separato, vale a dire la ProductSuggestionStorema entrambi contiene oggetti del tipo "Prodotto".

Se i negozi si comportano semanticamente diversi, ma condividono un sacco di logica di upload si potrebbe anche provare a costruire una base di prototipo / classe per i vostri negozi e quindi estendere i negozi specifici o esternalizzare la logica di upload in una classe di servizio.

Se siete preoccupati per le prestazioni, vale a dire un caricamento fa sì che tutti i componenti di ri-renderizzare, allora si può aggiungere un controllo all'interno shouldComponentUpdate.

Un buon esempio perché utilizzare un solo negozio potrebbe essere il caso in cui l'utente vuole chiudere la finestra, ma da qualche parte sul tuo sito web un upload è ancora in sospeso, allora la vostra visualizzazione applicazione principale ha solo per controllare un negozio. Anche arrivi potrebbero essere messe in coda facilmente in modo che la larghezza di banda non è esaurito, dal momento che tutte le immagini caricate passano attraverso un negozio.

Anche tenere a mente si può avere negozi che ascoltano altri negozi, come ad esempio la UploadHistoryStoremantiene un record timestamp degli ultimi 10 arrivi. Tutte le immagini caricate andare nello stesso secchio, ma se si dispone di un componente "Ultimi 10 Uploads" ha solo per ascoltare il "UploadHistoryStore"

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);
    }
});
Risposto il 05/10/2015 a 23:30
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more