フロントエンド開発のアーキテクチャである「SPA(Single Page Application)」について、開発に必要となる各種フレームワークの特徴や作り方の違いなどを紹介する連載。今回は、状態管理の方法やCSSの適用、単体テストの実装方法について比較し、ReactとAngular2の違いを明らかにする。
フロントエンド開発のアーキテクチャである「SPA(Single Page Application)」について、開発に必要となる各種フレームワークの特徴や作り方の違いなどを紹介する本連載「モダンなフロントエンド開発者になるためのSPA超入門」。
連載初回の「ゼロから学ぶ! Single Page Applicationの特徴と主なフレームワーク5選」ではSPAの特徴と取り巻く環境、フレームワークを紹介しました。前回は、そのフレームワークの中から、特に注目度が高い「React」「Angular2」を使い、簡単なTODOアプリの実装を通して、それぞれのフレームワークにおけるコンポーネントの実装方法の違いを比較しました。
最終回である今回は、より実践的な知識として、状態管理の方法やスタイルの適用、単体テストの実装方法について比較し、ReactとAngular2の違いを明らかにします。
クライアントでの処理量が増加するSPAアプリケーションでは、クライアントサイドでの状態(データ)管理が必須です。各フレームワークでは状態管理をするための仕組みが用意されていますので、React、Angular2それぞれにおける状態管理の方法を説明します。
併せて、Reactによる状態管理でよく使われるフレームワークであるReduxについても紹介します。
Reactの場合、各コンポーネントで状態を保持できますが、コンポーネントの再利用性を高めるために、なるべく状態を持たない(ステートレス)コンポーネントにすることが望ましいです。そのため、原則、親のコンポーネントで状態管理を行い、子コンポーネントは状態を持たないようにします。
本アプリケーションでは、親コンポーネントはApp.jsとして定義し、その中に複数の子コンポーネントを持つ構造となっていました。
そのため、Todoの状態などのデータについては親のApp.jsで管理し、子コンポーネントに受け渡しています。
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;
コンポーネントで保持する状態は、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: []};
}
次に、stateの更新方法について説明します。
addTodo(text) {
const { todos } = this.state;
this.setState(
{
todos: [...todos, { id: todos.length, text: text, isChecked: false}]
}
);
}
データの追加については、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>
);
}
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;
JavaScriptを中心としたWebアプリ開発の栄枯盛衰まとめ――LiveScriptからAngularJS/React.jsまで
いまさら聞けないReact、Virtual DOM、JSX超入門
アメブロでReactやIsomorphic Web Applicationを採用した理由――その成果と構成技術Copyright © ITmedia, Inc. All Rights Reserved.