FluxライブラリAltのデータフローについて

元記事：[Alt Flux Tutorial in Depth – The First Cycle](http://kenev.net/2015/08/23/alt-flux-tutorial-in-depth-the-first-cycle/)

Fluxライブラリに[Alt](http://alt.js.org/)を使っています。もともとはRefluxをつかっていたんですけど、DefinitelyTypedに定義ファイルが無いことに気づき、すでにDefinitelyTypedに定義ファイルがあるFluxライブラリはないかな〜って探してたところ、Altを見つけた次第です。（深い理由ではない。。。）

Altの[チュートリアル](https://github.com/goatslacker/alt-tutorial)をみてみたんですけど、個人的に微妙にトリッキーな部分があったので、理解を深めるため、忘れないために備忘録を残しておきます。 **理解が誤っている点など、ご指摘いただけるととってもうれしいです**。

# 概要
まず、頭の中を整理する為に図示しようとしたんですけど、Alt側で **自動的に** ごにょごにょしている場所とかあるので、若干初見ではソースが追いづらい印象を受けました。というのはさておき、`Component`、`Action`、`Store`の関係は概ね下の図みたいになるかと思います。

![-Blank UML - Alt.png](https://qiita-image-store.s3.amazonaws.com/0/38528/c543c1fc-cd51-6aa8-4d7b-ebda8e2c2473.png "-Blank UML - Alt.png")

# 詳細
## View
まず、`Locations`コンポーネントがマウントされて、`componentDidMount`にて`Location`の一覧を取得する為に`LocationStore.fetchLocations`が実行されます。`LocationStore`のコードを見てる人なら、いつ`fetchLocations`なんて定義したんだ？って最初は思うでしょうけど、そこについては次節にて説明します。いったんViewで行われていることはこれだけと思ってOK。

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

  render() {
    // edited for brevity
  }
});
```

## Action, Dispatcher, Store
`LocationStore`の`fetchLocations`関数については、`Alt`の`exportAsync`についてわかっていないとコードを追うのが困難になります。`exportAsync`で指定した`Source`（今回の場合`LocationSource`）で定義されている関数は、その`Store`の関数かのように使えるようになります（`mixin`のようなイメージ）。この挙動についての詳細は[docs](http://alt.js.org/docs/async/)の一読をおすすめします。ちなみにこの設定は`LocationStore`の`constructor`で行われています。↓

```js  
// LocationStore.js
class LocationStore {
  constructor() {
    // 省略
    
	// ここでLocationSourceの関数がLocationStoreの関数として
	// 公開される
    this.exportAsync(LocationSource);
  }
  // 省略
}
```

以上のことから、Viewで`LocationStore.fetchLocations()`が呼ばれた時は、実際には`LocationSource`の`fetchLocations`が実行されます。`Alt`の世界で`Source`はサーバとのデータやりとりを行う場所(`ajax`的ないろいろが発生する場所）になります。`Source`には色々と定義があるのですが、初回サイクルで注目すべきは`remote`と`loading`の2つです。`remote`はサーバにリクエストを投げる部分です。なので`Promise`が返却される場所になります。`loading`は、`fetchLocations`が呼ばれたときに発火する`Action`を定義します。今回であれば`LocationActions.fetchLocations`を発火させることで、`fetchLocations` Actionに興味がある人に通知することができるのです。 

```js
// LocationSource.js
var LocationSource = {
  fetchLocations() {
    return {
      remote() {
      	 // サーバ通信部分。データ取得依頼してPromiseを返却する場所
        return new Promise(function (resolve, reject) {
          // 省略
        });
      },

      // 省略

	  // fetchLocationsの時に発火するActionの定義 
      loading: LocationActions.fetchLocations 
    }
  }
}
```

ここまでを図示するとこんな感じに書けるかと思います。

![Alt Flux（日本語） - Alt - View.png](https://qiita-image-store.s3.amazonaws.com/0/38528/27c3fd73-2064-6241-92ee-d8ea105daaa6.png "Alt Flux（日本語） - Alt - View.png")

次に`LocationActions.fetchLocations`アクションが発火することで、`LocationStore`のハンドラ（`handleFetchLocations`）が実行されます。この中では、`Location`を再取得するので既存の`this.locations`を空の配列にしています。

```js
class LocationStore {
  constructor() {
    // 省略

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

    // 省略
    //
    this.exportAsync(LocationSource);
  }

  // 省略

  handleFetchLocations() {
    // fetchLocations時にはthis.locationsを空の配列に戻す
    this.locations = [];
  }

  // 省略
}
```

## View再び

`LocationStore`の`state`(this.locations)が変わることで、`AltContainer`を通して`AllLocations`に新しい`props`(locations)が渡されます。[AltContainer](http://alt.js.org/docs/components/altContainer/)については`Alt`を使う上ではきっと知っておかないといけない仕組みです。高階層Componentで、一番賢いComponentというイメージでしょうか（propsのエントリポイント的なポジション？）。`Store`と`Component`をいい感じに繋げてくれて、`Store`の`state`に変化があった場合に自動的に`Component`にpropsとして渡してくれるような仕組みです。が、かなり色々できるみたいなので、ただ`Store`と`Component`をつなげてくれる人っていうわけではないです。（詳細は私も勉強中。。。）

話を戻すと、`AllLocations`に新しい`props`(`locations`)が渡されるので`AllLocations`コンポーネントの`render`が走ります。この時、`LocationSource`の`Promise`がまだ`resolve`なりしてないので、`LocationStore.isLoading()`は`true`を返します。ゆえに、JSXは`ajax-loader.gif`を生成して、読み込み中の画面が生成されます。ちなみにこの`LocationStore.isLoading()`についても`exportAsync(LocationSource)`したときに自動的に公開される関数なので覚えておく必要ありです。なにかしら`Source`がペンディング中のリクエストがあるかどうか判定してくれる便利関数です。

```js
var AllLocations = React.createClass({
  // 省略
  
  render() {
    // 省略

    // LocationSourceのPromiseが解決していないので、ここはtrueになる
    if (LocationStore.isLoading()) {
      return (
        <div>
          <img src="ajax-loader.gif" />
        </div>
      )
    }

    // 省略
  }
});

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

  render() {
    return (
      <div>
        <h1>Locations</h1>
        <AltContainer store={LocationStore}>
          // AltContainerのおかげでLocationStoreとAllLocationsコンポーネントが
          // いい感じにつながってくれる
          <AllLocations />
        </AltContainer>

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

```

StoreとComponentについて図示すると以下のようになります。

![Alt Flux（日本語） - Alt - Store and Component.png](https://qiita-image-store.s3.amazonaws.com/0/38528/ec0b6bf9-20cf-b1a1-a0fb-c68050eeaf96.png "Alt Flux（日本語） - Alt - Store and Component.png")

そして、画面は読み込み中状態が表示されます。

![スクリーンショット 2015-08-23 21.26.07.png](https://qiita-image-store.s3.amazonaws.com/0/38528/bff31de7-1162-5054-f1cb-45d2270894c1.png "スクリーンショット 2015-08-23 21.26.07.png")


ここまでがLocation取得時の初回サイクルで起きる出来事です。次回は`Promise`が解決したときに何が起きているかについてまとめます。

ここまで読んで下さりありがとうございます。
見落としている点、説明が誤っている点があればご指摘お願いしますm(__)m