検索
連載

ReactとAngular2の使い方やコードの違いを状態管理、CSS適用、単体テストで比較するモダンなフロントエンド開発者になるためのSPA超入門(終)(1/3 ページ)

フロントエンド開発のアーキテクチャである「SPA(Single Page Application)」について、開発に必要となる各種フレームワークの特徴や作り方の違いなどを紹介する連載。今回は、状態管理の方法やCSSの適用、単体テストの実装方法について比較し、ReactとAngular2の違いを明らかにする。

Share
Tweet
LINE
Hatena

 フロントエンド開発のアーキテクチャである「SPA(Single Page Application)」について、開発に必要となる各種フレームワークの特徴や作り方の違いなどを紹介する本連載「モダンなフロントエンド開発者になるためのSPA超入門」。

 連載初回の「ゼロから学ぶ! Single Page Applicationの特徴と主なフレームワーク5選」ではSPAの特徴と取り巻く環境、フレームワークを紹介しました。前回は、そのフレームワークの中から、特に注目度が高い「React」「Angular2」を使い、簡単なTODOアプリの実装を通して、それぞれのフレームワークにおけるコンポーネントの実装方法の違いを比較しました。

 最終回である今回は、より実践的な知識として、状態管理の方法やスタイルの適用、単体テストの実装方法について比較し、ReactとAngular2の違いを明らかにします。

アプリケーションの状態管理

 クライアントでの処理量が増加するSPAアプリケーションでは、クライアントサイドでの状態(データ)管理が必須です。各フレームワークでは状態管理をするための仕組みが用意されていますので、React、Angular2それぞれにおける状態管理の方法を説明します。

 併せて、Reactによる状態管理でよく使われるフレームワークであるReduxについても紹介します。

Reactを使った状態管理

 Reactの場合、各コンポーネントで状態を保持できますが、コンポーネントの再利用性を高めるために、なるべく状態を持たない(ステートレス)コンポーネントにすることが望ましいです。そのため、原則、親のコンポーネントで状態管理を行い、子コンポーネントは状態を持たないようにします。

 本アプリケーションでは、親コンポーネントはApp.jsとして定義し、その中に複数の子コンポーネントを持つ構造となっていました。


図1 アプリケーションのコンポーネント構成イメージ

 そのため、Todoの状態などのデータについては親のApp.jsで管理し、子コンポーネントに受け渡しています。


図2 データの流れ
import React, { Component } from 'react';
//コンポーネントを読み込み
import Add from './Add';
import TodoList from './TodoList';
import '../styles/index.css';
 
class App extends Component {
  constructor(props) {
    super(props);
    // 関数のバインド
    this.addTodo = this.addTodo.bind(this);
    this.checkTodo = this.checkTodo.bind(this);	
    // stateの初期化
    this.state = {todos: []};
  }
 
  // 追加アクション
  addTodo(text) {
    const { todos } = this.state;
    this.setState(
      {
        todos: [...todos, { id: todos.length, text: text, isChecked: false }]
      }
    );
  }
 
  // チェックアクション
  checkTodo(id) {
    const todos = [...this.state.todos];
    todos.forEach((todo) => {
      if (todo.id === id) {
        todo.isChecked = !todo.isChecked;
      }
    });
    this.setState(
      { todos: todos }
    );
  }
 
  render() {
    const { todos } = this.state;
    // AddコンポーネントとTodoListコンポーネントの配置
    return (
      <div className="App">
        <Add addTodo={this.addTodo} />
        <TodoList todos={todos} checkTodo={this.checkTodo} />
      </div>
    );
  }
}
export default App;
App.js

 コンポーネントで保持する状態は、Reactが提供するstateに格納されます。Todoデータを格納するstateを用意するため、コンストラクタでstateの初期化を行います。

  constructor(props) {
    super(props);
    // 関数のバインド
    this.addTodo = this.addTodo.bind(this);
    this.checkTodo = this.checkTodo.bind(this);	
    // stateの初期化
    this.state = {todos: []};
  }
App.js(※stateの初期化部分)

 次に、stateの更新方法について説明します。

  addTodo(text) {
    const { todos } = this.state;
    this.setState(
      {
        todos: [...todos, { id: todos.length, text: text, isChecked: false}]
      }
    );
  }
App.js(※Todoデータ(state)の更新部分)

 データの追加については、Reactが提供するsetState関数を使ってstateの更新を行います。Todoを追加する処理では、stateに格納されているtodos配列に対して、新規に作成したTodoデータを追加しています。

 addTodo関数はAddコンポーネントで使用するため、propsの仕組みを使って、コンポーネントのレンダリングの際にAddコンポーネントに関数を受け渡しています。

  render() {
    const { todos } = this.state;
    // AddコンポーネントとTodoListコンポーネントの配置
    return (
      <div className="App">
        <Add addTodo={this.addTodo} />
        <TodoList todos={todos} checkTodo={this.checkTodo} />
      </div>
    );
  }
App.js(※レンダリング部分)

 Addコンポーネントでは、親から受け取ったaddTodo関数を登録ボタン(inputタグ)のonClickにセットすることで、Todoの追加処理を呼び出せるようにしています。

import React, { Component } from 'react';
import '../styles/add.css';
 
class Add extends Component {
  render() {
    const { addTodo } = this.props;
    return (
      <div className="add">
        <h2 className="title">TODOサンプルアプリケーション</h2>
        <input
          type="text"
          className="inputBox"
          placeholder="TODOを入力"
          ref={(ref) => this.inputBox = ref}
        />
        <input
          type="button"
          className="addBtn"
          value="登録"
          onClick={() => {
            addTodo(this.inputBox.value);
            this.inputBox.value = '';
          }}
        />
      </div>
    );
  }
}
 
export default Add;
Add.js

Copyright © ITmedia, Inc. All Rights Reserved.

       | 次のページへ
ページトップに戻る