Reactの基本的な構造

Reactはコンポーネントというものを定義し、画面表示まで構築する。その基本的な構造について説明する。

Reactを構成する3つのファイル

Reactアプリケーションには、基本的にいくつかのファイルが生成されている。

Reactを構成する3つのファイル

その中で、アプリケーション本体を構成するファイルは3つある。それぞれの役割を説明する。

  • index.js

    • srcフォルダに含まれている。メインプログラムといえる。ここでHTMLテンプレートとJavaScriptのコンポーネントを組み合わせ、レンダリングして実際に表示する。
  • App.js

    • srcフォルダにある。これはコンポーネントを定義するプログラムである。実際に画面に表示される内容などはここで定義される。
  • index.html

    • publicフォルダにある。メインプログラムであるindex.jsに対応するHTMLテンプレートファイルである。このファイルが直接表示されるのではなく、index.jsによって読み込まれ、レンダリングされた結果が表示される。

ビルドすると構成が変わる

注意すべき点は、これらはNode.jsアプリケーションとして動作する場合の構成であるということだ。サーバーにNode.jsがあり、そのまま起動するのであればこのままでもよいが、通常のWebサーバーに配置して使う場合、アクセス時にindex.jsが読み込まれてレンダリングされる方法は少し無理がある。

このような場合は、前に説明したようにnpm run buildでアプリケーションをビルドする。するとフォルダ構成が変わる。フォルダのルートにindex.htmlが新しく生成され、その中でindex.jsに相当するスクリプトが実行された表示を作れるようになる。

実際に試してみれば分かるが、index.htmlはともかく、そこから呼び出されるスクリプトはビルド時に新しく生成され、コード自体がまったく異なるものになっている。自動生成されているためか改行もなく、人が読むには難しい。つまり、ビルドして生成されたものは、もはや「人が編集するもの」とは考えないということである。一般的なプログラミング言語ではソースコードをコンパイルするとバイトコードを生成するが、それに近いものだと考えればよい。

したがって、私たちがプログラミングするのはあくまでビルド前のindex.jsApp.jsである。修正する場合もこれらを編集し、再度ビルドして生成されたものを配布する。これまでの「HTMLやJavaScriptは書いたものがそのままサーバーにアップロードされ、ブラウザに読み込まれて動作する」という常識は捨てる必要がある。

Reactでは「開発時に書くコード」と「実際に配布されるコード」はまったく異なる。Reactはコンパイラ言語で開発するような感覚で作る必要がある。

(ただし、Node.jsそのものがサーバーにあり、Node.jsアプリケーションとして実行するのであれば話は別である。この場合はいわばインタープリタがサーバーにあり、コンパイルしなくても動作するような状況だと考えてよい)

index.jsアプリケーションのプログラム

生成されたソースコードを見てみよう。

アプリケーションのプログラムについて

メインプログラムであるindex.jsを説明する。以下にソースコードを示し、内容を順番に説明する。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

import文について

最初に複数のimport文が書かれているが、これは外部モジュールをロードするものである。このimport文はJavaScriptではあまりなじみがないかもしれないが、ES6、つまりECMAScript 6 Editionでサポートされる機能である。Reactでは「Babel」というES6対応のトランスコンパイラを使っているため、このようなES6の機能を利用できる。

最初にreactreact-domというモジュールをロードしており、これらがReactの本体である。また、次の./App./index.cssはここで使用するコンポーネントとスタイルシートである。これらもimportでロードする。

ReactDOM.render

次に、ReactDOMオブジェクトのrenderメソッドを実行している。これはこのプログラムで実行する唯一の処理である。コンポーネントを指定した位置に入れてレンダリングを行うもので、次のように実行する。

ReactDOM.reder(コンポーネント, 組み込み先要素);

第1引数には、App.jsで定義しているAppコンポーネントを指定している。そして第2引数には、rootというIDの要素を指定する。すると、Appコンポーネントがrootタグに含まれたコードとしてレンダリングされ、出力される。

JSXについて

ここではrenderの引数に<App />というものが指定されている。これはAppコンポーネントのタグだが、JavaScriptの引数に直接HTMLタグが書かれているため、不思議に思うかもしれない。

これはJSXという機能を利用したものである。おそらく「JavaScript Expression」の略だろう。このJSXは、HTMLタグをそのままJavaScriptコード内に書ける機能である。単独タグだけでなく、タグの中に別のタグが含まれる複雑なものも処理できる。

<App />という値を書くことで、<App />タグに定義されたユーザー定義コンポーネントをrenderに指定している。

index.htmlテンプレート

続いて、Webページのテンプレートであるindex.htmlを見てみよう。以下にソースコードを示す。長いコメントがあるが、ここでは省略した。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <!--
      ... 中略 ...
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <!--
      ... 中略 ...
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <!--
      ... 中略 ...
    -->
  </body>
</html>

このコードはそれほど難しくない。いくつか説明する。

%PUBLIC_URL%について

ヘッダー部分を見ると、<link>タグにhref="%PUBLIC_URL%/favicon.ico"のような値が設定されている。この%PUBLIC_URL%はReactが提供する接頭辞で、公開サイトのURLが設定される。

id="root"タグについて

<body>部分に<div id="root"></div>というタグがある。このid="root"はどこかで見た覚えがあるはずだ。そう、index.jsReactDOM.renderの引数でdocument.getElementById('root')として指定していたものである。指定したrootが、この<div id="root"></div>タグを指している。つまり、このタグ部分に<App />コンポーネントが含まれるようになっている。

このindex.htmlテンプレートの役割はこれだけである。ただ<div id="root"></div>タグを用意し、ここにコンポーネントが含まれるテンプレートである。

App.js Appコンポーネント

アプリケーションの表示部分は「コンポーネント」によって作られる。このソースコードがどうなっているか見てみよう。

基本的にApp.jsというスクリプトファイルが用意されており、ここにAppというコンポーネントのコードが記述されている。その内容を以下に示す。

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

コードの内容を整理してみよう。

import文について

まずimport文で複数のモジュールを取り込んでいる。最初の行にimport React {Component} from 'react';という文があるが、これがReactのコンポーネント関連のオブジェクトをロードする部分である。その後の2行は、logo.svgApp.cssをロードするための文である。

Appクラスについて

ここではAppクラスというものが定義されている。JavaScriptでもクラスを作成できる。ES6というエディションでクラス定義が可能になっている。ReactがES6であることを思い出そう。ここではAppクラスを次のように定義している。

class App extends Component {...}

Componentクラスを継承してAppクラスを生成していることが分かる。このComponentがコンポーネントの基盤となるクラスである。これを継承することでコンポーネントとして動作する。

renderメソッドについて

このAppクラスにはrenderというメソッドが1つ含まれている。これは次のように書かれる。

render () {
    return ...;
}

returnで返される値が、そのままレンダリングの内容として処理される。ここではreturnする値は次のような形になっている。

return (<div className = "App"> ... 省略 ... </div);

HTMLタグが書かれている。これが「JSX」である。ここで返されるタグが、そのままAppコンポーネントの表示内容として出力される。

 

これでReactアプリケーションの基本的な内容が分かった。「コンポーネントを定義し、それを組み込んでレンダリングする」というのが、Reactで行っているすべてである。