Fluxとはデザインパターンの一種で、データが一方向に流れる(flux)パターンです。
React.js
単体では、Viewを担うコンポーネントだけです。
そこでFluxでは、アクション、ディスパッチャー、ストアを新たに導入します。
データが一方向に
アクション -> ディスパッチャー -> ストア -> コンポーネント -> アクション
と流れていきます。
Fluxの設定
Fluxをインストールします。
npm -S install flux
Chap 9 サンプルアプリの準備
このチュートリアルでは、Todoリストを一覧で表示するアプリを作成します。
(Todoの追加もできる。)
コンポーネント: Page1.js(修正), Todo.js
ストア : TodoStore.js
ディスパッチャー: dispatcher.js
アクション: TodoAction.js
クラス図もどき
まずはじめに、ストアTodoStore.js
とコンポーネントPage1.js
Todo.js
を作成します。
(まだ、アクション、ディスパッチャーは作りません。)
ストアがTodoリストのデータtodos
を保持します。
Todoリストを取得するgetAll()
インターフェースをコンポーネントに提供します。
import { EventEmitter } from "events";
class TodoStore extends EventEmitter {
constructor() {
super();
this.todos = [ // Todoリストを保持します。
{
id: 10,
text: "Go Shopping",
complete: false
},
{
id: 20,
text: "Pay Bills",
complete: false
},
];
}
// Todoリストを返します。
getAll() {
return this.todos;
}
}
const todoStore = new TodoStore;
export default todoStore;
import React from "react";
import Todo from "./Todo";
import TodoStore from "./TodoStore";
export default class Page1 extends React.Component {
constructor() {
super();
this.state = {
todos: TodoStore.getAll(), // Todoリストをロードします。
};
}
render () {
const {todos} = this.state;
// mapで Todoエレメントを動的に作成。
const todoList = todos.map((todo) => {
return <Todo key={todo.id} {...todo}/>; // text={todo.text} complete={todo.complete}
});
return (
<div>
<h3>My Todo List</h3>
<ul>{todoList}</ul>
</div>
);
}
}
Todoリストの1アイテムを表現するコンポーネント
import React from "react";
export default class Todo extends React.Component {
render () {
const { complete, text } = this.props;
return (
<li>
<span>{complete}</span>
<span>{text}</span>
</li>
);
}
}
実行します。上のスクショのように、Todoリストが表示されればOKです。
Chap 10 ストアのイベント処理
ストアでイベントを発生させ、コンポーネントでイベントを受け取ります。
新たに、Todoを追加するインターフェースaddTodo(text)
を作成します。
追加後、イベントを発生させます。
class TodoStore extends EventEmitter {
...
// Add a new Todo to TodoStore.
addTodo(text) {
const id = Date.now(); // ユニークIDを適当に採番
// Todoを新規追加
this.todos.push({
id,
text,
complete: false,
});
this.emit("change"); // イベントを発生
}
getAll() {
return this.todos;
}
}
const todoStore = new TodoStore;
window.td = todoStore; // デバッグ用
export default todoStore;
イベントリスナーを登録します。
イベントを受け取ったら、ストアからTodoリストをリロードします。
ステートが変わるので、子コンポーネントTodo
も自動更新されます。
export default class Page1 extends React.Component {
...
componentWillMount() { // ビューに初めて描画されるときに一回だけ呼ばれます。
TodoStore.on("change", () => { // イベントを受け取る
this.setState({
todos: TodoStore.getAll(), // Todoリストをリロード
});
});
}
render () {
...
とりあえず、コンソールからデバッグします。
td.addTodo("new task!")
と入力します。
スクショのように、Todoリストが追加されればOKです。
Chap 11 ディスパッチャー
ディスパッチャーdispatcher.js
を新規作成します。
import {Dispatcher} from "flux";
export default new Dispatcher;
import { EventEmitter } from "events";
import dispatcher from "./dispatcher"; // ディスパッチャーのインポート
class TodoStore extends EventEmitter {
...
getAll() {
return this.todos;
}
// ディスパッチャーからアクションが渡されます。
handleActions(action) {
console.log("TodoStore received an action", action);
switch (action.type) { // 追加のアクション`CREATE_TODO`か?
case "CREATE_TODO": { // 自分で勝手に決めた定数
this.addTodo(action.text); // アクションを追加する。で、イベント発生。
}
}
}
}
const todoStore = new TodoStore;
window.td = todoStore; // デバッグ用
// ディスパッチャーにコールバックを登録
dispatcher.register(todoStore.handleActions.bind(todoStore));
window.dp = dispatcher; // デバッグ用
export default todoStore;
再度、コンソールからデバッグします。
dp.dispatch({type:"CREATE_TODO", text:"new task!"})
と入力します。
Todoリストが追加されればOKです。
Chap 12 アクション
最後に、アクションを作成し、コンポーネントとディスパッチャーの橋渡しをします。
アクションTodoAction.js
を新規作成します。
import dispatcher from "./dispatcher";
export function addTodo(text) {
// ディスパッチャーを呼びます。
dispatcher.dispatch({type:"CREATE_TODO", text});
}
コンポーネントに追加ボタンを設置して、アクションを呼びます。addTodo(text)
import * as TodoAction from "./TodoAction" // アクションをインポート
export default class Page1 extends React.Component {
...
addTodo() {
TodoAction.addTodo("New Task!"); // アクションを呼びます
}
render () {
const {todos} = this.state;
const todoList = todos.map((todo) => {
return <Todo key={todo.id} {...todo}/>; // text={todo.text} complete={todo.complete}
});
return (
<div>
<button onClick={this.addTodo.bind(this)}>Add!</button>
<h3>My Todo List</h3>
...
実行します。Add!
ボタンを押します。
Todoリストが追加されればOKです。