Alt Flux Tutorial in Depth – The First Cycle

このエントリーをはてなブックマークに追加

Alt Flux Tutorial – Some Additional Information

Why Alt???

I’ve started using Alt as my Flux library recently, and the only reason was that the type definition file (d.ts) for TypeScript was available – until then, I was using Reflux.

Overview

Well, as I started using Alt by looking at the tutorial, is was a bit hard for me to understand the unidirectional data flow. So I’ve decided to create a diagram to make it easier to depict what is happening. I’m not going in depth about the code and what is already written in the Getting Started section of the official site and I’m assuming that you have looked at the entire code. If any information in this post seems strange, feel free to leave some comments. It would extremely help me and whoever else reading this post.

The Diagram

Fetching the Location List

As I tried to write a data flow diagram for this process, I’ve noticed it was hard to write it as a unidirectional data flow because of the LocationSource. Anyway, the simplest diagram would probably look like this.

-Blank UML - Alt

This diagram does not quite illustrate how the code is written. The Locations React component calls LocationStore‘s fetchLocation when the componentDidMount.

// Locations.jsx
componentDidMount() {
  LocationStore.fetchLocations();
}

But this fetchLocations method is not LocationStore‘s method because it was automagically exported by calling exportAsync(LocationSource) inside LocationStore‘s constructor – therefore, being able to call LocationStore.fetchLocations(). In addition, LocationSource‘s fetchLocations method is called when LocationStore.fetchLocations() is called which is then connected to LocationActions‘s fetchLocations. Therefore, I’ve simplified the diagram so that it looks like the react component’s initial LocationStore.fetchLocations() is calling the LocationAction‘s fetchLocations, protecting the Flux’s unidirectional architecture.

In Depth

The View

First of all the AllLocations will get mounted and LocationStore.fetchLocations(); gets executed.

// Locations.jsx
var Locations = React.createClass({
  componentDidMount() {
    LocationStore.fetchLocations();
  },

  render() {
    // edited for brevity
  }
});
The Action, Dispatcher, Store

As mentioned above, this call actually executes LocationSource‘s fetchLocations(). This is because it was hooked (like a mixin) as explained in the docs inside LocationStore‘s constructor.

// LocationStore.js
class LocationStore {
  constructor() {
    // edited for brevity

    this.exportAsync(LocationSource); // <- hooked here
  }
  // edited for brevity
}

LocationSource‘s fetchLocations makes an asynchronous call to the server (which is stubbed out in the tutorial as a setTimeout function) and returns a Promise. It also triggers the LocationActions.fetchLocations action to notify the LocationStore that it is going to load the locations.

// LocationSource.js
var LocationSource = {
  fetchLocations() {
    return {
      remote() {
        return new Promise(function (resolve, reject) {
          // edited for brevity
          }, 250);
        });
      },

      // edited for brevity

      loading: LocationActions.fetchLocations // triggered action on fetch
    }
  }
}

The diagram in detail would look like this.

-Blank UML - Alt - View

Now, the LocationStore listens to the LocationActions.FETCH_LOCATIONS hence, handleFetchLocations gets called – which resets the this.locations with an empty array.

class LocationStore {
  constructor() {
    // edited for brevity

    // listening and registering event handlers
    this.bindListeners({
      handleUpdateLocations: LocationActions.UPDATE_LOCATIONS,
      handleFetchLocations: LocationActions.FETCH_LOCATIONS, 
      handleLocationsFailed: LocationActions.LOCATIONS_FAILED,
      setFavorites: LocationActions.FAVORITE_LOCATION
    });

    // edited for brevity
    //
    this.exportAsync(LocationSource);
  }

  // edited for brevity

  handleFetchLocations() {
    // resets the locations array on fetch
    this.locations = [];
  }

  // edited for brevity
}
The View Again

As the LocationStore‘s state changes, the AllLocations component receives the new props through the AltContainer automagically – see the official documents on what actually happens. The LocationStore.isLoading() returns true because the LocationSource‘s Promise hasn’t resolved yet – and by the way, LocationStore.isLoading method is also automagically exposed via the exportAsync method – which then makes the AllLocations JSX end up as a ajax-loader.gif.

var AllLocations = React.createClass({
  // edited for brevity

  render() {
    // edited for brevity

    // this returns true on fetch and before the promise gets resolved
    if (LocationStore.isLoading()) {
      return (
        <div>
          <img src="ajax-loader.gif" />
        </div>
      )
    }

    // edited for brevity
  }
});

var Locations = React.createClass({
  componentDidMount() {
    LocationStore.fetchLocations();
  },

  render() {
    return (
      <div>
        <h1>Locations</h1>
        <AltContainer store={LocationStore}>
          // the AllLocations component automagically gets connected to the LocationStore
          <AllLocations />
        </AltContainer>

        <h1>Favorites</h1>
        <AltContainer store={FavoritesStore}>
          <Favorites />
        </AltContainer>
      </div>
    );
  }
});

In a diagram in detail, the components and the store are connected as below.

Alt Flux - Alt - Store and Component

Hence, the view ends up looking like this.

スクリーンショット 2015-08-23 21.26.07

This is what happens in the first cycle. I’ll explain what happens after the Promise gets resolved in the next post.

Written on August 23, 2015
このエントリーをはてなブックマークに追加