Skip to content

Instantly share code, notes, and snippets.

@randylien
Forked from thomasboyt/loading.md
Last active August 29, 2015 14:10
Show Gist options
  • Save randylien/f352b4f6795e68e3903c to your computer and use it in GitHub Desktop.
Save randylien/f352b4f6795e68e3903c to your computer and use it in GitHub Desktop.

I've been struggling to come up with a good pattern for handling loading state in Flux (specifically using Fluxxor, though I think this is an issue for any implementation).

When I say "loading state," what I mean is state in a store that tracks:

  • Whether the data handled by the store was loaded
  • Whether the store is currently attempting to load data
  • Whether the data loaded successfully or errored
  • The error message, if it errored

Here's my first (very simple) pass at this, a store mixin called LoadingStoreMixin.js:

module.exports = {
  // Call in the constructor and any time the data is to be "reset"
  initLoadingState: function() {
    this.loaded = false;
    this.loading = false;
    this.didError = false;
    this.error = null;
  },

  // Call when loading is begun (e.g. onLoadStart)
  startLoading: function() {
    this.loaded = false;
    this.loading = true;
    this.didError = false;
    this.error = null;
  },

  // Call when loading succeeds (e.g. onLoadSuccess)
  finishLoading: function() {
    this.loaded = true;
    this.loading = false;
    this.didError = false;
    this.error = null;
  },

  // Call when loading fails (e.g. onLoadErrror)
  errorLoading: function(err) {
    this.loaded = false;
    this.loading = false;
    this.didError = true;
    this.error = err;
  }
};

(Fluxxor doesn't yet support mixins out of the box, but it's easy enough to fudge with e.g. _.merge on the hash passed to Fluxxor.createStore).

The intended usage is to manually call these functions from within your load messages:

var ContactsActions = {
  load: function() {
    this.dispatch('contacts:load');

    someAjax({
      url: '/contacts',
      method: 'GET'
    }).then((resp) => {
      this.dispatch('contacts:loadSuccess', resp);
    }, (err) => {
      this.dispatch('contacts:loadError', err);
    });
  }
};

var ContactsStore = Fluxxor.createStore(_.merge({
  initialize: function() {
    this.contracts = null;
    this.initLoadingState();

    this.bindActions(
      'contacts:load', 'onLoadContacts',
      'contacts:loadSuccess', 'onLoadContactsSuccess',
      'contacts:loadError', 'onLoadContactsError'
    );
  },

  onLoadContacts: function() {
    this.startLoading();
    this.emit('change');
  },

  onLoadContactsSuccess: function(resp) {
    this.finishLoading();
    this.contacts = resp.data;
    this.emit('change');
  },

  onLoadContactsError: function(err) {
    this.errorLoading(err);
    this.emit('change');
  }
}, LoadingStateMixin);

Then, your component can use the loading, loaded, didError, and error attributes as expected.

There's a lot of limitations this mixin has (for example: it can't really handle >1 loadable resource at a time :<), but I feel like it's better than nothing. Ideally, Flux implementations like Fluxxor will start including more robust versions of patterns like this to ease some of the initial pains of boilerplate, as well as to provide best practices for storing data and state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment