めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

バックエンドエンジニアのための(かどうかは本当はよく分からないけど、とにかく書いてみる)React 入門(パート3)

何の話かと言うと

enakai00.hatenablog.com

上記の続きになります。今回からは、新しいアプリケーションを作成していきますが、まずは、React のビルド処理とパッケージマネージャーについて簡単に説明しておきます。

React のビルド処理

React では、JSX と呼ばれる Javascript の拡張言語でコードを書きます。これを Babel と呼ばれるコンパイラーで一般的なブラウザー上で実行可能な Javascript に変換します。Babel は Node.js で動作するため、React の開発環境には Node.js が必要となります。また、本番環境にデプロイする最終的なコードは、Webpack を使って最適化されたコンパクトなイメージにまとめられます。前回のビルド処理でディレクトリー「build」以下に生成された内容は、「Babel によるコンパイル+Webpack によるパッケージング」が実行された結果になります。

パッケージマネージャー

React のコードでは、さまざまなライブラリーパッケージをインポートして使用することができます。ここでは、開発環境にライブラリーをインストールするためのパッケージマネージャーとして、yarn を使用しています。次回以降の手順で出てくる様に、「yarn add <パッケージ名>」でディレクトリー「node_modules」以下に新しいパッケージをインストールします。インストールしたパッケージのバージョン情報は、「package.json」に記録されており、記録されたパッケージは「yarn install」コマンドで再インストールできます。したがって、開発中のコードを GitHub で管理する場合、「node_modules」以下は .gitignore で無視しておき、新規に git clone した際は、「yarn install」で必要なパッケージを再インストールするという運用を行います。

アプリケーション起動の流れ

続いて、最小構成の「Hello, World!」アプリケーションを作って、コンパイルされたバイナリーがどのように動作するかを説明します。はじめに、作業用ディレクトリーに新しいアプリケーションの雛形を作成します。

% cd ~/Documents/work 
% npx create-react-app hello_world

ディレクトリー「hello_world」以下に雛形が作成されていますが、実際にコーディングしていくファイルは、ディレクトリー「public」以下の静的コンテンツとディレクトリー「src」以下の動的コンテンツ(JSXで記述するコード)になります。ここでは、雛形として用意されたファイルは削除して、最小限のファイルのみを改めて用意します。favicon は再利用したいので、favicon.ico だけを残して、既存のファイルを削除します。

% cd hello_world
% cp public/favicon.ico .
% rm -rf public/*
% rm -rf src/*
% mv favicon.ico public/

次に、以下のファイルを用意します。

public
├── favicon.ico    ← 再利用    
└── index.html     ← 新規作成   
src
├── components
│   └── App.js    ← 新規作成   
└── index.js      ← 新規作成   

新しく作成するファイルが3つありますが、それぞれの内容を順に説明していきます。

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Hello, World!</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

これは、アプリケーションの画面を作るベースとなる HTML ファイルです。"root" という ID の div ブロックがあるだけで、これでは何も表示されないように思われますが、実際には、これを表示した後に index.js が実行されるようにコンパイル処理が行われます。index.js の中で、この div ブロックの中に実際のアプリケーションのコンポーネントを配置します。

index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from './components/App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

ここでは、index.html で用意した "root" という ID のブロックに React が生成するコンポーネントを配置しています。通常はアプリケーション全体のレイアウトをまとめて生成するコンポーネントを1つだけ配置して、実際のアプリケーションの中身は、そのコンポーネント内で実装していきます。今回は、「App」という名称のコンポーネントを配置しており、その中身は「components/App.js」で定義します。

components/App.js
export const App = () => {

  const element = (
    <div>
      Hello, World!
    </div>
  );

  return element;
}

ここでは関数 App() を定義しています。Javascript を使い慣れない方には不思議な書き方に見えるかもしれませんが、「() => {...}」という記法で無名関数(Python の lambda のようなもの)を定義して、それを変数 App に代入しています。また、頭に export を付けることにより、他のファイルでこの関数をインポートして参照できるようにしています。先ほどの「index.js」の3行目では、この関数をインポートしています。

そして、React のコンポーネントを定義する関数は、HTML 要素を返り値として渡します。ここでは、変数 element に代入した HTML 要素が返却されます。これにより、index.js の <App /> の部分がこの HTML 要素に置換されます。返却する HTML 要素はツリー状にネストして構いませんが、最上位の親要素は1つだけに限る必要があります。複数の要素を並置して返したい場合は、次のように空タグ(正式にはフラグメント要素と言います)を利用してまとめます。

  const element = (
    <>
      <div>
        Hello, World!
      </div>
      <div>
        Good bye, World!
      </div>
    </>
  );

ちなみに・・・変数 element に HTML 要素を代入する、というのは、もちろん普通の Javascript でできることではありません。ここは、React の JSX 記法の拡張部分で、丸括弧 () でHTML 要素をまとめることで、それ自体を変数に代入可能なオブジェクトとして扱うことができます。この HTML 要素には、先ほどの <App /> のように React の関数として定義したコンポーネントを含めることができて、正確には、「React 要素」と呼ばれるオブジェクトになります。

というわけで、Hello, World! アプリケーションが完成しました。これを実行すると、「components/App.js」で定義した HTML 要素(つまり、「Hello, World!」)が画面に表示されます。パート1で見たように、次のコマンドを実行すると、ローカルの開発用サーバーで実行することができます。

% yarn start

次回予告

前回の最後に、『次回からは「リバーシ」を作成していきます』と書きましたが、残念ながらリバーシまで辿り着きませんでした。次回からは、本当にリバーシの作成に入りたいと思います。

パート4はこちらです。

enakai00.hatenablog.com