Fluxアーキテクチャのサイクルをコードリーディングで一通り確認する

FluxはFacebookが提唱したUIアーキテクチャです。この文書では、[React JS Tutorialsのソースコード](https://github.com/learncodeacademy/react-js-tutorials)をコードリーディングすることで、Fluxアーキテクチャのサイクルを一通り確認します。

Fluxの図：
![fluximg.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/1c7cfbf0-3fae-c214-af8c-e2731d91f200.jpeg)

## 準備
node.jsのインストールは完了しているものとします。

[React JS Tutorialsのソースコード](https://github.com/kabosu3d-lab/react-js-tutorials)をダウンロードしてください(※バージョン違いが生じないようにフォークしてあります)。

ダウンロードしたらプロジェクトのルートディレクトリで、

```sh
cd 3-flux/
npm i
npm run dev
```

します。

そして、[localhost:8080](http://localhost:8080)をブラウザで開いてください。

下記のようなページが表示されたら準備完了です。

<img width="1079" alt="スクリーンショット 2019-05-19 8.48.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/30da8850-331f-a1fb-7346-a26a7fbb63e7.png">

## コードリーディング
### 画面とFluxアーキテクチャの関係を確認する
`src/js/pages/Todos.js`を開いてください。今ブラウザに表示されているTodoリスト画面が定義されています。この画面はFluxアーキテクチャと４箇所で関係しますので、順に見ていきます。

一つめの箇所です。12行目を見てください。

```js
this.state = {
  todos: TodoStore.getAll(),
};
```

この`TodoStore`はFluxのStoreです。ここからデータを取得し、stateの初期値にセットしています。

次に二つめの箇所です。25行目の`getTodos()`を見てください。

```js
  getTodos() {
    this.setState({
      todos: TodoStore.getAll(),
    });
  }
```

ここでも`TodoStore`(FluxのStore)からデータを取得し、stateを更新しています。

この`getTodos()`が実行されるのが三つめの箇所です。

17行目を見てください。

```jsx
  componentWillMount() {
    TodoStore.on("change", this.getTodos);
  }

  componentWillUnmount() {
    TodoStore.removeListener("change", this.getTodos);
  }
```

componentWillMountで`TodoStore`(FluxのStore)が変化した時に`getTodos()`をするように登録をしています。componentWillUnmountの時には登録を解除しています。

ここでFluxの図との関係を確認しましょう。図の「React Views」は今見ている`Todos`コンポーネントです。図の「Store」が`TodoStore`です。図の「Change Event & Store Query」は「Change Event」「Store Query」の二つに分けることができ、「Change Event」 は下記です(17行目、再掲)。

```jsx
  componentWillMount() {
    TodoStore.on("change", this.getTodos);
  }

  componentWillUnmount() {
    TodoStore.removeListener("change", this.getTodos);
  }
```

「Store Query」は下記です（25行目、再掲）。

```jsx
  getTodos() {
    this.setState({
      todos: TodoStore.getAll(),
    });
  }
```

つまり「Store」の「Change Event」を「View」が購読登録し、「Change Event」が発生したら「Store Query」を実行して、更新されたデータを読み取りにいくわけです。

ただし、初回だけは特別に「Change Event」の発生にかかわらず、データを読み込んでいます(12行目、再掲)。

```jsx
this.state = {
  todos: TodoStore.getAll(),
};
```

コードリーディングに戻りましょう。31行目を見てください。これがTodosコンポーネントがFluxと関係している部分の四つめの箇所です（これで全部です）。

```jsx
  reloadTodos() {
    TodoActions.reloadTodos();
  }
```

この`TodoActions.reloadTodos()`はUIでReloadボタンがクリックされたときに呼ばれています(44行目)。

```jsx
<button onClick={this.reloadTodos.bind(this)}>Reload!</button>
```

Fluxの図で言う「User Interaction」はReloadボタンを押すことです。図の「Action Creaters」はこれにより呼ばれる`TodoActions.reloadTodos()`です。

ここまでで`Todos`コンポーネントのFluxアーキテクチャとの関係を確認できました。

## Fluxサイクルの確認

ここからはReloadボタンを押した時の動作に話を絞り、Fluxサイクルを確認していきます。

おさらいすると、Todosコンポーネント(図の「React Views」)でReloadボタンが押されると(図の「User Interactions」)`TodoActions.reloadTodos()`(図の「Action Creater」)が実行されるのでした。

Action Createrの実装を見て見ましょう。`src/js/actions/TodoActions.js`の17行目を見てください。

```jsx
export function reloadTodos() {
  // axios("http://someurl.com/somedataendpoint").then((data) => {
  //   console.log("got the data!", data);
  // })
  dispatcher.dispatch({type: "FETCH_TODOS"});
  setTimeout(() => {
    dispatcher.dispatch({type: "RECEIVE_TODOS", todos: [
      {
        id: 8484848484,
        text: "Go Shopping Again",
        complete: false
      },
      {
        id: 6262627272,
        text: "Hug Wife",
        complete: true
      },
    ]});
  }, 1000);
}
```

21行目でまずDispatcherにFETCH_TODOSアクションをdispatchします。22行目で(APIアクセスを擬似的に表現するため)setTimeoutが実行され、timeoutしたらRECEIVE_TODOSアクションをdispatchしています。

このDispatcherは一体どう言う動きをするのでしょうか。

`src/js/dispatcher.js`を見るとFluxのライブラリを読み込んでいます。ここではFluxライブラリの実装に立ち入ることはせず、Dispatcherがどういう動きをするのかを説明するにとどめます。

```js
import { Dispatcher } from "flux";

export default new Dispatcher;
```

Dispatcherにはコールバックを登録することができます。何らかのアクションがdispatchされると必ずコールバックが実行されます。

コールバックを登録している部分を確認します。`src/js/stores/TodoStore.js`を見てください。55行目でコールバックを登録しています。

```js
dispatcher.register(todoStore.handleActions.bind(todoStore));
```

そして38行目を見てください。コールバックの中ではActionの種類に応じてStoreをアップデートする動作が実行されます。

```js
  handleActions(action) {
    switch(action.type) {
      case "CREATE_TODO": {
        this.createTodo(action.text);
        break;
      }
      case "RECEIVE_TODOS": {
        this.todos = action.todos;
        this.emit("change");
        break;
      }
    }
  }
```

このようにアクションのdispatchに応じてStoreが更新されます。

そして最初に説明した通り、Storeの更新に応じて「Change Events」が発行されて 「Store Query」 が行われ、「React Views」が更新されるということになります。

これでFluxアーキテクチャのサイクルを一通り確認することができました。

最後にFluxサイクルとコードの紐付けをまとめます（「React Views」から時計回りの順）

![fluximg.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198108/1c7cfbf0-3fae-c214-af8c-e2731d91f200.jpeg)

- 「React Views」 = `Todos`コンポーネント
- 「User Interaction」 = Reloadボタンを押すこと
- 「Action Creaters」= `TodoActions.reloadTodos()`
- 「Actions」=`RECEIVE_TODOS`
- 「Dispatcher」 = FluxライブラリのDispatcher
- 「callbacks」= `TodoStore`にある`handleActions()`
- 「Store」 = `TodoStore`
- 「Change Event & Store Query」
    - 「Change Event」 = Viewが購読登録する、Storeの変化イベント
    - 「Store Query」 = ViewによるStoreの状態取得


以上