ReactとAngular2の使い方やコードの違いをコンポーネント単位で比較する:モダンなフロントエンド開発者になるためのSPA超入門(2)(3/4 ページ)
フロントエンド開発のアーキテクチャである「SPA(Single Page Application)」について、開発に必要となる各種フレームワークの特徴や作り方の違いなどを紹介する連載。今回は、ReactとAngular2を使い、SPA開発のイメージをつかむとともに、それぞれの違いを明らかにしていく。
Reactコンポーネントの作成
Todoコンポーネント
まず、ReactではTODOリストの各行を生成しているTodoコンポーネントは次のようになっています。
import React from 'react'; import '../styles/todo.css'; // コンポーネントを宣言 const Todo = (props) => { // 親コンポーネントから値を受け取る const { todo, checkTodo } = props; // チェック済みのTODOか判定 if (todo.isChecked) { return ( <li className="checked" onClick={() => checkTodo(todo.id)}>{todo.text}</li> ) } else { return ( <li onClick={() => checkTodo(todo.id)}>{todo.text}</li> ) } }; // コンポーネントをエクスポート export default Todo;
冒頭にJavaScriptでは見慣れない「import」宣言があります。こちらはECMAScript 2015で策定されている仕様で、外部のファイルを参照して利用でき、JavaScriptでの大規模開発がし易くなります。もちろん、そのままではブラウザ上では動作しませんので、スターターツールに組み込まれているモジュール管理ライブラリ「webpack」がファイル間の依存関係を解決し、1つのJavaScriptファイルにバンドルします。
TODOのテキスト部分は親から受け取った値を表示するようになっており、親からデータを受け取る「props」と呼ばれる仕組みを使って、親コンポーネントから子コンポーネントへデータの受け渡しを行います。
親のTodoListコンポーネントから「todo」オブジェクトの形でデータを受け取り、todoオブジェクト内に格納されている「todo.text」にアクセスし、テキストデータを取り出しています。
if (todo.isChecked) { return ( <li className="checked" onClick={() => checkTodo(todo.id)}>{todo.text}</li> ) } else { return ( <li onClick={() => checkTodo(todo.id)}>{todo.text}</li> ) }
コンポーネントのView部分の実装は「JSX」と呼ばれるHTMLライクな構文を使って実装します。JSXで記述したコードをReactがDOMに変換し、画面に出力します。JSXではHTMLとほぼ同じタグが記述可能ですが、あくまでHTMLライクな構文であるため注意が必要です。
TODOのリスト部分は単純なul/liタグを使ってリストを作成しているため、子のTodo.jsでは中身のliタグを生成する作りになっています。親であるTodoList.jsからもらったTODOのデータを使い、liタグを生成します。今回は未チェックとチェック済みのTODOで表示を切り替えるため、「isChecked」フラグを使ってJSXの出し分けを行っています。
また、HTMLと異なる点の1つとして「className」があります。JSXではclassを指定するときにはclassNameと記述することで出力されるHTMLにclassを適用できます。
TodoListコンポーネント
Todo.jsコンポーネントの親であるTodoListコンポーネントは以下の通りです。
import React from 'react'; // コンポーネントを読み込み import Todo from './Todo'; import '../styles/todoList.css'; const TodoList = (props) => { // 親コンポーネントから値を受け取る const { todos, checkTodo } = props; const list = []; // TODOデータの数だけリストを作成 todos.forEach((todo, index) => list.push(<Todo key={index} todo={todo} checkTodo={checkTodo} /> )); return ( <ul className="todoList"> {list} </ul> ); } // コンポーネントをエクスポート export default TodoList;
子であるTodoコンポーネントをimportし、for文でTODOの数だけTodoコンポーネントを描画します。
Appコンポーネント
最後に、アプリケーションの最上位の親コンポーネントにあたるAppコンポーネントを見てみます。
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: []}; } // TODO追加アクション addTodo(text) { const { todos } = this.state; this.setState( { todos: [...todos, { id: todos.length, text: text, isChecked: false }] } ); } // TODOチェックアクション 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コンポーネントでは「state」と呼ばれる機能を使ってTODOデータを管理し、子コンポーネントへデータの受け渡しを行っています(データの管理について詳しくは第3回で説明します)。
画面を構成しているAddコンポーネントとTodoListコンポーネントを配置し、TODOのデータは「todos」オブジェクトにデータを詰めてTodoListコンポーネントへ渡します。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- JavaScriptを中心としたWebアプリ開発の栄枯盛衰まとめ――LiveScriptからAngularJS/React.jsまで
@ITが誕生した2000年頃はJavaScriptが不遇だった時代。そこから現在のような人気のプログラミング言語になるまでには、どのような歴史があったのか。15周年を迎えた@ITの豊富なWeb開発関連記事とともに振り返る。 - いまさら聞けないReact、Virtual DOM、JSX超入門
Facebookが公開しているJavaScriptライブラリ「React」について、その概要や特徴、Webページに導入する方法や基本的な使い方を解説します。 - アメブロでReactやIsomorphic Web Applicationを採用した理由――その成果と構成技術
2004年から続くブログサービス「アメブロ」が2016年9月にシステムをリニューアル。本連載では、そこで取り入れた主要な技術や、その効果を紹介していく。初回は、Isomorphic Web Applicationについて。