10
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

React.js + ES6 + WebPack チュートリアル (Flux編)

Last updated at Posted at 2016-06-12

前回の続き

Fluxとはデザインパターンの一種で、データが一方向に流れる(flux)パターンです。

React.js単体では、Viewを担うコンポーネントだけです。
そこでFluxでは、アクションディスパッチャーストアを新たに導入します。

データが一方向に

アクション -> ディスパッチャー -> ストア -> コンポーネント -> アクション

と流れていきます。

Fluxの設定

Fluxをインストールします。

npm -S install flux

Chap 9 サンプルアプリの準備

このチュートリアルでは、Todoリストを一覧で表示するアプリを作成します。
(Todoの追加もできる。)

Screen Shot 2016-06-12 at 8.49.26 AM.png

コンポーネント: Page1.js(修正), Todo.js
ストア : TodoStore.js
ディスパッチャー: dispatcher.js
アクション: TodoAction.js

クラス図もどき

Screen Shot 2016-06-12 at 10.47.10 AM.png

まずはじめに、ストアTodoStore.jsコンポーネントPage1.js Todo.jsを作成します。
(まだ、アクション、ディスパッチャーは作りません。)

ストアがTodoリストのデータtodosを保持します。
Todoリストを取得するgetAll()インターフェースをコンポーネントに提供します。

TodoStore.js
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;
Page1.js
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アイテムを表現するコンポーネント

Todo.js
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>
        );
    }
}

:arrow_forward: 実行します。上のスクショのように、Todoリストが表示されればOKです。

Chap 10 ストアのイベント処理

ストアでイベントを発生させ、コンポーネントでイベントを受け取ります。

新たに、Todoを追加するインターフェースaddTodo(text)を作成します。
追加後、イベントを発生させます。

TodoStore.js
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も自動更新されます。

Page1.js
export default class Page1 extends React.Component {
...
    componentWillMount() { // ビューに初めて描画されるときに一回だけ呼ばれます。
        TodoStore.on("change", () => { // イベントを受け取る
            this.setState({
                todos: TodoStore.getAll(), // Todoリストをリロード
            });
        });
    }

    render () {
...

:arrow_forward: とりあえず、コンソールからデバッグします。
td.addTodo("new task!")
と入力します。
スクショのように、Todoリストが追加されればOKです。

Screen Shot 2016-06-12 at 9.19.29 AM.png

Chap 11 ディスパッチャー

ディスパッチャーdispatcher.jsを新規作成します。

dispatcher.js

import {Dispatcher} from "flux";

export default new Dispatcher;
TodoStore.js
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;

:arrow_forward: 再度、コンソールからデバッグします。
dp.dispatch({type:"CREATE_TODO", text:"new task!"})
と入力します。
Todoリストが追加されればOKです。

Screen Shot 2016-06-12 at 9.46.49 AM.png

Chap 12 アクション

最後に、アクションを作成し、コンポーネントとディスパッチャーの橋渡しをします。

アクションTodoAction.jsを新規作成します。

TodoAction.js
import dispatcher from "./dispatcher";

export function addTodo(text) {
    // ディスパッチャーを呼びます。
    dispatcher.dispatch({type:"CREATE_TODO", text});
}

コンポーネントに追加ボタンを設置して、アクションを呼びます。addTodo(text)

Page1.jsp
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>
...

:arrow_forward: 実行します。Add!ボタンを押します。

Todoリストが追加されればOKです。

Screen Shot 2016-06-12 at 10.06.12 AM.png

10
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?