最終更新日:170711 原本2017/01/04 

CodeZine(コードジン)

Reactの概要と基礎技術要素を理解する

基礎からはじめるReact入門 第1回

 本連載は、Reactアプリを開発するための基礎を身につけることを目的としたものです。Reactは、コーディング方法が少し独特なため、最初のハードルが高めに感じる方も多いかと思います。しかし、一度その方法を身につければ高い開発生産性を発揮します。本連載では、はじめてReactに触れる方でも無理なく開発スキルを身につけられるよう1つずつステップを踏んで解説していきます。連載では、Reactの概念・文法・作法などといった基礎的な事項を学んだ後、Fluxアーキテクチャを採用した本格的なアプリ開発の手法を体験する、という流れを予定しています。また、連載の最後にはReactの標準ツールの活用方法についても紹介します。

対象読者

  • JavaScriptとWeb開発の基礎に理解がある方
  • Reactに興味/関心があり、これから学び始める方

前提環境

 筆者の検証環境は以下の通りです。

  • macOS Sierra 10.12
  • Node.js v6.6.0/npm 3.10.3
  • React 15.4.0

 Node環境が準備できていない方は別途インストールしてください。Mac環境であればnodebrew、Windows環境であればnodist等のバージョン管理ツールの利用をおすすめします。

Reactの主な特徴

 ReactはUIを構築するためのFacebook製オープンソースJavaScriptライブラリです。

図1 公式Webサイトトップページ(https://facebook.github.io/react/)- 2016年11月時点
図1 公式Webサイトトップページ(https://facebook.github.io/react/)- 2016年11月時点

 2011年にFacebookのニュースフィードにデプロイされて以来、Instagram、Airbnb、Netflix、Paypal、Uberなど数々のアプリケーションで活用されています。Reactの公式サイトには、以下のような特徴が挙げられています。

  1. 宣言型
  2. コンポーネントベース
  3. 一度学べばどこでも使える

 Reactはこれらの特徴により大規模なWebアプリケーション開発に適したライブラリとなっています。1.と2.の意味については本連載が進む中で、実感いただければと思います。

 3.は、Reactはクライアントサイドの描画だけでなく、Nodeを使ったサーバーサイドレンダリングに対応している他、ReactNativeというモバイルアプリ開発フレームワークを利用することで、モバイル開発にも対応しているということを意味しています。Reactを学ぶことで、デスクトップクライアント、サーバー、そして、モバイルのアプリが開発できるということをうたっているわけです。

SPAとVirtual DOM

 実際の開発を始める前に、SPAとVirtual DOMについて少し触れたいと思います。SPA(Single Page Application)とは、一つのページで構成されたアプリで、以下のようなメリットがあります。

  • デスクトップアプリのような高いUXを提供できる。
  • クロスプラットフォームに対応できる。
  • デプロイが簡単になる。

 反面、ページ遷移などのためにDOM操作が必須であることから、以下のような技術的な課題もありました。

  • DOM操作を直接行う場合、手続き型のプログラミングスタイルとなるため、コードが複雑になり
    保守性が下がる。
  • DOMの更新には時間がかかるため、アプリのパフォーマンスが低下する。

 Reactはプログラミングスタイルを宣言型に規定することで1つ目の課題を、Virtual DOMという仕組みを導入することで2つ目の課題をクリアしました。

 Virtual DOMを簡単に説明すると、メモリ上に保持された、DOMのコピーのようなものです。
ユーザーイベントやサーバーイベントによりデータの更新が発生し、DOMを再描画する必要が出た場合、画面のDOMではなくVirtual DOMを更新します。Virtual DOMが更新されると、ReactはVirtualDOMと画面のDOMを比較し、変化した部分だけを見つけます。最後に、Reactは変化した部分だけをアップデートします。Virtual DOMデータの更新が発生してから実際にDOMの更新を行うまでのプロセスはメモリ上のみで行い、DOM更新も必要最小限の範囲で行うことで高速化を実現しているのです。

開発環境

 現在はcreate-react-appというツールがリリースされており、新しいアプリを作る際には最良の手段であると公式ドキュメントにも記載があります。本稿でも、その方法を紹介します。以前はReactの環境を構築するために、コンパイルツール(Babel)やビルドツール(Browserify、 Webpack)等多くのツールが必要でしたが、このツールを使えば簡単に環境ができあがります。
ただし、既存のプロジェクトにReactを組み込む場合はnpmを使ってreactモジュールをインストールするのと、BrowserifyやWebpackを使ったビルド環境の構築が必要になります。

コマンドの実行

 以下のコマンドにより、ツールのインストールからアプリの実行まで行えます。このツールで新規に作成したアプリは、内部的に上で紹介したビルドツール等が自動設定されているため、npm run buildコマンドを実行することで簡単にビルドまで行えます。

# グローバル環境にツールをインストール
$ npm install -g create-react-app

[省略]

# プロジェクトの作成
$ create-react-app hello-world

[省略]

Success! Created hello-world at <path_To_hello-world>/hello-world
Inside that directory, you can run several commands:

  npm start
    Starts the development server.


# 開発環境でのテスト実行
$ cd hello-world
$ npm start

Starting the development server...

Compiled successfully!

The app is running at:

  http://localhost:3000/

Note that the development build is not optimized.
To create a production build, use npm run build.

 エラーが発生せずにコマンドが完了すると、ブラウザが起動し、以下のようなページが表示されます。トップページのアドレスは「http://localhost:3000」です。

図2 React標準ツールで作成されるテンプレートページ
図2 React標準ツールで作成されるテンプレートページ

 ツールインストール後に、create-react-appコマンドを実行すると、reactを動作させるために必要なnpmモジュールのインストールを含め、アプリのひな形が作成されます。npm startコマンドにより、nodeサーバーの起動、およびBabelによるES6のコードの変換、Webpackによるモジュールの依存関係が解決などの処理が行われ、開発環境上でアプリが動作するという流れです。

 詳細なコマンド実行結果は配布サンプルを参照してください。本番環境リリース時には、パフォーマンスを最適化のためにnpm run buildコマンドの実行によりbuildフォルダに生成されるファイル群をデプロイします。

Reactプロジェクトの構成

 自動生成したプロジェクトの構成を見てみましょう。create-react-appツールにより作成されたプロジェクトは、以下のような階層になっています。

図3 React標準ツールによって作成されたプロジェクト
図3 React標準ツールによって作成されたプロジェクト

 さまざまな種類のファイルがありますが、それぞれのファイル/フォルダの役割は以下のようになっています。

表1 Reactプロジェクトの概要
フォルダ ファイル 役割
node_modules * Reactアプリが動作するために必要なnodeモジュール
public index.html ブラウザに表示されるhtmlページ
src App.css App.jsにより描画されるDOMに適用されるCSS
App.js Reactコンポーネントを定義するJS(※)
index.js index.htmlを操作するためのJS
index.css index.htmlに適用されるCSS
package.json ライブラリの依存関係等、npmに関する挙動を定義する

 (※)コンポーネントについては別途紹介します。現時点ではhtmlの部品を描画するものと理解してください。

 最初の理解のために特に重要なのは「public/index.html」、「src/index.js」、「src/App.js」の3ファイルです。以下はそれぞれのファイルの関係を図解したものです。

図4 Reactプロジェクトのファイルの関係
図4 Reactプロジェクトのファイルの関係

[コラム]ES6(ECMAScript6)の構文について

 Reactで作成されるテンプレートでは、ES6が適用されています。ES6は2015年に策定された新しいJavaScriptの仕様で、新しい機能の追加とともに構文も刷新されています。ここでは、class構文とモジュール構文について補足をします。

 ES5までの仕様では、JavaScriptにクラスという概念はありませんでしたが、ES6で追加されました。クラスの考え方はJavaをはじめとした他のオブジェクト指向の言語と同じです。以下のようにclass構文でクラス名を宣言し、extends句でクラスを継承できます。もちろん、関数の定義なども可能になっています。

class App extends Component {
    [省略]
}

 次にモジュール構文です。モジュールという単位でクラスや関数を管理する機能が追加されています。これにより、nodeのライブラリはもちろん、自作したクラスや関数も自由に外部のクラスに連携することが容易になりました。App.js内の最初と最後に、import句とexport句が記述されています。import句では、reactモジュールの中からReactとComponentというメンバーのみを読み込んでいます。また、export (export default)句ではファイル内で定義したAppクラスを外部に公開しています。

import React, { Component } from 'react';

export default App;

 順に処理を追っていきましょう。

(1)コンポーネントの宣言

 React.Componentクラスを継承したAppコンポーネントを宣言します。現時点ではrenderメソッド内で返されている「<div className="App">…</div>」という要素を描画するクラスが宣言されていることを理解いただければ十分です。コンポーネントについては次節以降に説明します。

(2)モジュールのエクスポート

 ES6の構文に基づき、Appコンポーネントをエクスポートしています。

(3)モジュールの読み込み

 (2)でExportされたコンポーネントを読み込みます。

(4)DOMの操作

 ReactDOM.renderメソッドの実行によりindex.html内のroot要素にAppコンポーネントを挿入し、(1)の<div>内の要素を描画します。ReactDOM.renderメソッドの構文は以下のとおりです。

[構文]renderメソッド
ReactDOM.render(
  element,
  container,
  [callback]
)

element:描画するタグ要素、container:コンテナ要素、callback:描画コールバック

JSX Syntax

 前節において、Component宣言時には使われていたXML風な記述方法はJSXと呼ばれるものです。一度理解してしまえば難しいものではありませんが、初見だと戸惑う方もいるかと思います。コードを触りながら慣れていきましょう。index.jsに少し変更を加えます。

リスト1 src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

const element = <p>Hello, world</p>;

ReactDOM.render(
  element,
  document.getElementById('root')
);

 上記の変更を加えて保存してからブラウザの画面を見ると、”Welcome to React”の画面からテキストで”Hello World”の画面に切り替わっているかと思います(nodeサーバーを停止していた場合は、再度npm startコマンドでサーバーを起動してください)。このようにJSXによりHTML要素を変数として保持し、ReactDOM.renderメソッドで画面に描画するスタイルはReactの基礎の
1つです。

図5 JSXを利用した描画
図5 JSXを利用した描画

 JSXは基本的にはHTMLを変数化しているという理解で問題ないのですが、ビルド時にはJavaScriptに変換されてからコンパイルが実行されます。そのため、classやfor属性といったJavaScriptの予約語はJSXでは利用できません。代わりにclassNameやhtmlForといったプロパティ名を利用する必要があります。また、JSXは下記のように変数を利用することやタグに子要素を持たせることも可能です。

const element1 = <img src={user.profilePhoto}>    // {}演算子による変数表現

const element2 = (                                // 子要素のあるdivタグ
  <div>
    <h1>Good Evening</h1>
    <h2>Its cold tonight! Take care of yourself</h2>
  </div>
);

 JSXはシンプルにさまざまなタグ要素を表現することができますが、内部ではReact.createElementというメソッドが実行されています。以下の二つのコードは同一です。

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

 以下はReact.createElementメソッドの構文です。

[構文]createElementメソッド
React.createElement(
  type,
  [props],
  [...children]
)
type:タグ要素/Reactコンポーネント、porps:タグの属性、children:子要素

コンポーネントの概要

 冒頭で、コンポーネントベースであることがReactの特徴の一つであると述べました。コンポーネントとは、機能を兼ね備えたUIの部品です。Reactではコンポーネントを組み合わせてアプリを構築することで、コンポーネントごとに状態を管理すると同時に、複雑なUIを一つの部品としてまとめることができます。

 コンポーネントには関数型とクラス型という2種類の宣言方法があります。以下の2つは同一の
コンポーネントです。

function Greeting(props) {
  return <h1>Hello, {props.name}</h1>;
}
class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

 関数型は簡潔にコードを記述できるというメリットがあります。また、関数型は状態を管理できない(ステートレスである)という特徴があります。一方、クラス型は状態を管理できます(ステートフルです)。状態変化に応じてViewを更新したいようなコンポーネントを作成する場合に効果を発揮します。

 関数型とクラス型のどちらを利用するかは状況に応じて判断する必要があります。全てのコンポーネントをクラス型で作成してしまうと、アプリが大きくなって1つの親要素の下に大量の子要素がひも付いた場合に、全てのコンポーネントの状態を管理することが非常に難しくなります。とはいえ、全てのコンポーネントをステートレスにする必要はなく、場合によりコンポーネントをステートレスにするか、ステートフルにするか使い分けるべきです。

コンポーネントの利用

 次にコンポーネントを描画するコードを示します。index.jsを書き換えることで動作は確認できます。

リスト2 src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

function Greeting(props) {
  return <h1>Hello, {props.name}!</h1>;    //(2
}

const element = <Greeting name="Tom"/>;    //(1)

ReactDOM.render(
  element,
  document.getElementById('root')
);
図6 コンポーネントを利用した描画
図6 コンポーネントを利用した描画

 (1)でelementを生成する際に、注目すべき点が2つあります。まず1つ目はGreetingタグを宣言している点です。ユーザー定義の名称のコンポーネントとして要素を生成することができます。そしてもう1つ目はnameというタグ属性を設定している点です。Reactにおいて、コンポーネント宣言時に設定したタグ属性は、propsオブジェクトとしてコンポーネントに渡されます。propsを通してコンポーネントに渡された属性は、(2)のようにname変数として取り出されます。

あとがき

 本稿ではReactの概要と基礎となる技術要素についてできるだけ丁寧に解説することを心がけました。Reactはコンポーネントを組み合わせたアプリケーションの構築を強制させることで、コードの保守性や可読性を上げ、特に大規模アプリケーション開発における効率を上げてくれます。本稿がこれからReactを学ぶ方が最初の一歩を踏み出すための一助となれば幸甚です。

 次回はコンポーネントに関する続きの解説とさまざまなHTMLタグを描画する方法について紹介します。