React の使い方

最近では JavaScript のライブラリとして React を使用して開発されている方も多いのではないでしょうか。 そこで React の使い方についてまとめてみます。 いまさら感がスゴイですが、誰かのお役に立てれば幸いです。

React とは?

react_thumb.png

React は、UI(ユーザインターフェース)をコンポーネントと呼ばれる部品を使って構築するための JavaScript ライブラリです。 Meta 社(旧:Facebook 社)製です。 大規模で複雑なアプリケーションを作成する際に React が採用されていることが多く、React について難しい印象を持たれている方も多いのではないでしょうか。 しかしながら、React そのもののコンセプトはそれほど難しいものではありません。

コンポーネント

Web システムの世界では、様々な理由から HTML や JavaScript といった、言語ごとの大きい縦の区切りでソースコードを分割するのが普通でした。 しかしその場合、UI 部品の「処理」と「見た目」がそれぞれ別々のファイルに記述されてしまうことになるため、 UI 部品を再利用することが少し困難でした。

React を使用すると、UI 部品の「処理」と「見た目」の両方を「コンポーネント」という単位で1つにまとめることが可能になります。 コンポーネントという単位でまとめることで、UI 部品として再利用することが容易になります。 また、開発を行う際にも、コンポーネントという単位で作業を分担することができるようになるため、 大人数での作業がしやすくなったりします。

component.png

では、実際にどうやってコンポーネントを作成するか見てみましょう。 下記の例を見てください。 これは、ボタンをただ表示するだけのコンポーネントになります。 React のコンポーネントは、JavaScript の関数として記述します。 関数の中にそのコンポーネントの「処理」を記載し、その「見た目」を return で返します。 普通の JavaScript の関数との違いは return でコンポーネントの見た目を返すかどうかぐらいでしかありません。

例:ボタンを表示するコンポーネント「MyButton」
JavaScript
function MyButton() {

	// コンポーネントの「処理」をここに記述する
	// 例えば、ボタンの状態や、ボタンが押された時の処理などを記述する

	// コンポーネントの「見た目」を返す
	return (
		<button>This is a button</button>
	);
}

え? JavaScript ファイルの中に HTML タグが直接書かれているように見える? これではシンタックスエラーになって動かないのではないかですって??? ...そうです。その通りです。 これは JSX と言いまして、JavaScript の中に HTML タグのようなマークアップを直接記述できるようになる拡張構文になります。 JSX の詳細については後述しますので、まずはコンポーネントの振舞いについて注目してください。

今度は上記の例で作成したコンポーネント「MyButton」を、別のコンポーネントの中で使用する方法を見てみましょう。 コンポーネントの中で、別のコンポーネントを使用するには、 return で返すマークアップの中に、使用したいコンポーネントを HTML のタグと同様にマークアップの形式で記述します。 通常の HTML のタグと区別するために、コンポーネントの名前の先頭は常に大文字にする必要があるので注意してください。 このようにマークアップとして記述することで、好きな位置に好きなコンポーネントを埋め込むことができます。

例:セクションを表示するコンポーネント「MySection」
JavaScript
function MySection() {
	return (
		<section>
			<h1>This is a h1</h1>
			<MyButton />
		</section>
	);
}

上記の2つのコンポーネントを実際に使用すると下記のような結果になります。 ちゃんと2つのコンポーネントが混ざった見た目になっていることを確認してください。

出力結果
<section>
	<h1>This is a h1</h1>
	<button>This is a button</button>
</section>

React のコンポーネントがどんなものなのかイメージできましたでしょうか。 React のコンポーネントとは、マークアップを返す JavaScript の関数でしかありません。 実際に使用する際には、コンポーネントの状態を管理したり、 別のコンポーネントにパラメーターを渡したり、 表示を切り替えたり、ループしたり、イベントハンドラを設定したりといった細かな処理が必要になるでしょう。 もっと詳しい説明については公式のドキュメントを見てもらった方が良いと思いますので、そちらを参照してください。

JSX

JSX はコンポーネントの「見た目」を記述するために使用されている JavaScript の拡張構文です。 JSX を使用することで、HTML タグを直接 JavaScript ファイルの中に書くことができます。 とはいえ、これは実際には HTML タグと完全に同じものではありません。 JSX には HTML タグとの違いがいくつか存在しています。 例えば、JSX では、全てのタグを閉じる必要があります。 <br> ではなく、<br /> と記述しなければなりません。 お気付きの方もいると思いますが、この記述方法は XML と同じです。 かなり昔に一時期流行った XHTML を思い出していただければわかりやすいのではないでしょうか。 つまり、JSX とは JavaScript の中に直接書ける XML のようなものなのです。

React では JSX を JavaScript の中で HTML タグを記述するためのシンタックスシュガーとして使用します。 JSX を使用せずに React を使用することもできるのですが、その場合は HTML タグに相当する関数呼び出しを自前で記述することになり、 かなりメンドクサイことになるので、JSX は使用した方が良いと思います。

例えば、上記の例で使用した「MySection」コンポーネントを、JSX を使用せずに記述すると下記のような記述になります。 JSX を使用した例と比べてみてください。

例:コンポーネント「MySection」で JSX を使用しない場合
JavaScript
function MySection() {
	return React.createElement(		// <section> ~ </section>
		"section",
		null,
		React.createElement(		// <h1> ~ </h1>
			"h1",
			null,
			"This is a h1"
		),
		React.createElement(MyButton, null)		// <MyButton />
	);
}

つまり、JSX を使用すると、記述されたタグの1つ1つを React.createElement() という関数の呼び出しに自動で変換してくれるのです。 JSX が無いとどれくらいメンドクサイか理解いただけますでしょうか。

とはいえ、JSX は JavaScript 本来の機能ではありません。 そのため、ブラウザで直接動作させることはできません。 JSX を動作させるためには、JSX から実際に動作する JavaScript へ変換する必要があります。 この変換は Babel や TypeScript などで行うことができます。 具体的な変換方法は後述します。

React のインストール

さっそくですがインストールしていきましょう。

React は、コンポーネントの「見た目」の部分(つまり、JSX を使用している部分)を仮想 DOM という、内部オブジェクトとして保持しています。 そして、その仮想 DOM の内容を元にして、実際の画面に描画処理を行っています。 そのため、仮想 DOM を扱う React 本体「react」パッケージと、その仮想 DOM を元に実際の画面に描画するためのレンダラーの2つが必要になります。

レンダラーは、Web ブラウザ向けの「react-dom」パッケージ(React DOM)や、 Android や iOS などのネイティブアプリ向けの「react-native」パッケージ(React Native)、 テスト用の「react-test-renderer」パッケージなどがあります。 なお、この記事では、Web ブラウザ向けの内容を記述していきますので注意してください。

Web ブラウザ向け 「react」パッケージ + 「react-dom」パッケージ
Android、iOS 向け 「react」パッケージ + 「react-native」パッケージ
テスト用 「react」パッケージ + 「react-test-renderer」パッケージ

Web ブラウザ向けの場合は、「react」パッケージと「react-dom」パッケージの2つが必要になります。 「react」パッケージで仮想 DOM を作成し、「react-dom」パッケージでその仮想 DOM を実際の HTML の DOM に反映させるといった使い方になります。

CDN を使用する

script タグで CDN から直接 React を読み込んで使用することができます。 下記の例では、unpkg を使用していますが、 他にも jsDelivrcdnjs など、 npm パッケージを提供する CDN なら何でも使用することができます。 もちろん、このファイルをダウンロードして、自分で配信することもできます。

例:CDN として unpkg を使用する場合
<!-- react パッケージの読み込み -->
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>

<!-- react-dom パッケージの読み込み -->
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

npm を使用する

npm を使用してインストールする場合は、下記のコマンドを実行します。 npm の使い方がわからないという方は、「Node.js と npm の使い方(その1:概要)」を参考にしてください。

例:「react」パッケージと「react-dom」パッケージをインストールする場合
npm install --save-dev react react-dom

npm を使用してインストールした場合は、使用したいファイルで読み込む必要があります。 CommonJS の場合は require()、ES Modules の場合は import を使用して読み込みます。

例:CommonJS の場合
JavaScript
// react パッケージの読み込み
const React = require('react');

// react-dom パッケージの読み込み
const ReactDOM = require('react-dom/client');
例:ES Modules の場合
JavaScript
// react パッケージの読み込み
import React from 'react';

// react-dom パッケージの読み込み
import ReactDOM from 'react-dom/client';

webpack と組み合わせて JSX を変換する

JSX を変換するためには、前述のとおり Babel や TypeScript などを使用する必要がありますが、 この記事では webpack で Babel Loader を使用して変換する方法を記載します。 webpack の使い方がわからないという方は、「webpack の使い方」を参考にしてください。

webpack で Babel Loader を使用して JSX を変換するには、 「babel-loader」パッケージと、「@babel/preset-react」パッケージの2つが必要です。 「babel-loader」パッケージは webpack で Babel を使用するためのもので、「@babel/preset-react」パッケージは Babel で React(JSX)を使用するためのものといった感じでしょうか。

例:「babel-loader」パッケージと「@babel/preset-react」パッケージをインストールする場合
npm install --save-dev babel-loader @babel/preset-react

「babel-loader」パッケージと、「@babel/preset-react」パッケージがインストールできたら、 webpack の設定ファイルで、それらを使用するように設定します。

webpack.config.js
module.exports = {
	mode: 'production',
	entry: {
		main: './src/index.js',
	},
	output: {
		path: __dirname + '/dist',
		filename: '[name].js',
	},
	module: {
		rules: [
			{
				test: /\.(?:js|mjs|cjs)$/,
				exclude: /node_modules/,
				use: {
					loader: 'babel-loader',
					options: {
						presets: [
							['@babel/preset-react'],
						],
					},
				},
			},
		],
	},
};

JSX の変換は2種類

JSX から JavaScript への変換(JSX トランスフォーム)には、旧バージョンと新バージョンの2種類が存在します。

旧バージョンの変換

Babel 8 より前ではこれがデフォルトです(この記事の作成時点では Babel 7.22.10 が最新) JSX が JavaScript に変換される際、React.createElement() に変換されます。 しかし、これには少し問題があります。

JSX が React.createElement() に変換されるということは、 JSX を使用している全てのファイルで React オブジェクトが使用できる状態を作り出さなければならないということ意味します。 React 本体を script タグを使用して読み込んでいる場合は、React オブジェクトがグローバルに存在しているので問題はありません。 npm パッケージの方の React を require()(CommonJS の場合)や import(ES Modules の場合)を使用して読み込んでいる場合は、JSX を使用している全てのファイルで、 React オブジェクトを require() / import しておく必要があります。 例え、ソースコード上で React オブジェクトを全く使用していないように見えたとしても、 JSX の変換後には必ず React オブジェクトが使われている状態になってしまうからです。

例:ES Modules の場合
JavaScript(ES Modules)
// React オブジェクトは下記のコード上のどこにも使用していないように見えるかもしれませんが、
// JSX の部分が React.createElement() に変換されるため必要になります
import React from 'react';

function MyButton() {
	return (
		// この部分が React.createElement() に変換される
		<button>This is a button</button>
	);
}

新バージョンの変換

新バージョンでは、JSX が JavaScript に変換される際、_jsx() に変換されます。 また、自動で _jsx()require() / import を追加してくれるようになります。 つまり、旧バージョンで問題となった require() / import の無駄な記述が必要なくなります。

新バージョンは Babel 7.9.0 以降で使用できますが、デフォルトでは有効になっていません。 そのため、使用する際には Babel の設定を変更する必要があります。 Babel 8 以降ではこちらがデフォルトになるとのことなので、 設定がメンドウという方は Babel のバージョンアップを待っても良いかもしれません。

新バージョンを使用するには、webpack の「@babel/preset-react」パッケージの設定で、 runtimeautomatic を指定します。 ちなみに旧バージョンを使用する場合は、classic を指定します。

webpack.config.js
module.exports = {
	mode: 'production',
	entry: {
		main: './src/index.js',
	},
	output: {
		path: __dirname + '/dist',
		filename: '[name].js',
	},
	module: {
		rules: [
			{
				test: /\.(?:js|mjs|cjs)$/,
				exclude: /node_modules/,
				use: {
					loader: 'babel-loader',
					options: {
						presets: [
							['@babel/preset-react', {runtime: 'automatic'}],
						],
					},
				},
			},
		],
	},
};

基本的な使い方

さて、ここまででようやく実際に使用するための準備ができました。 ということで実際に動かしてみましょう。

React で作成したコンポーネントを HTML として描画するには、 レンダラーである ReactDOM オブジェクトを使用します。 HTML 上での描画位置を .createRoot() で指定し、描画する内容を .render() で指定します。 .render() の引数は JSX なので注意してください。 なお、React を script タグで読み込むか、require() / import で読み込むかによって、 書き方に多少の違いがありますので注意してください。

JavaScript(ES Modules)
// react パッケージの読み込み(script タグで読み込む場合は不要)
// React オブジェクトは下記のコード上のどこにも使用していないように見えるかもしれませんが、
// JSX の変換が旧バージョンの場合は React.createElement() に変換されるため必要になります
// JSX の変換が新バージョンの場合は自動で import されるため不要です
import React from 'react';

// react-dom パッケージの読み込み(script タグで読み込む場合は不要)
import ReactDOM from 'react-dom/client';

// 「MyButton」コンポーネント
function MyButton() {
	return (
		<button>This is a button</button>
	);
}

// 「MySection」コンポーネント
function MySection() {
	return (
		<section>
			<h1>This is a h1</h1>
			<MyButton />
		</section>
	);
}

// React を実行
// HTML の id="app" の位置に「MySection」コンポーネントの内容を描画する
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<MySection />);
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="utf-8">
	<title>My React App</title>
	<!-- react パッケージの読み込み(require() / import で読み込む場合は不要)-->
	<script defer src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
	<!-- react-dom パッケージの読み込み(require() / import で読み込む場合は不要)-->
	<script defer src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
	<!-- JavaScript を読み込み(webpack で変換したファイル) -->
	<script defer src="./dist/main.js"></script>
</head>
<body>
	<p>This paragraph is a part of HTML.</p>
	<!-- この位置に描画される -->
	<div id="app"></div>
	<p>This paragraph is also a part of HTML.</p>
</body>
</html>

ESLint と組み合わせる

ESLint と組み合わせてコードのチェックを行ってみましょう。 まず前提として、ESLint の使い方がわからないという方は、「ESLint の使い方」を参考にしてください。

デフォルトの ESLint では JSX を扱えません。 ESLintで JSX を扱えるようにするためには、「eslint-plugin-react」パッケージをインストールする必要があります。

「eslint-plugin-react」パッケージをインストールする

「eslint-plugin-react」パッケージをインストールするには、下記のコマンドを実行します。

npm install --save-dev eslint-plugin-react

「eslint-plugin-react」パッケージがインストールできたら、ESLint の設定ファイルを下記のように変更します。 extendsplugin:react/recommended を追加することで JSX が扱えるようになります。 また、settings.react.version で React のバージョンを指定する必要があります。 detect を指定すると使用されている React のバージョンを自動で設定してくれます。 現状では指定しないと Warning が表示されるようです。 将来的にはデフォルトが detect になり、指定しなくても良くなるようです。

.eslintrc.cjs
module.exports = {
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended",
	],
	"settings": {
		"react": {
			"version": "detect",
		},
	},
};

script タグで読み込んでいる場合

React を script タグで読み込んでいる場合は、 ESLint からは React オブジェクトと ReactDOM オブジェクトが見つかりませんので、 globals に追加してエラーにならないように設定します。

.eslintrc.cjs
module.exports = {
	"globals": {
		"React": "readonly",
		"ReactDOM": "readonly",
	},
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended",
	],
	"settings": {
		"react": {
			"version": "detect",
		},
	},
};

JSX の変換が新バージョンの場合

JSX の変換が新バージョンの場合は、extendsplugin:react/jsx-runtime を追加します。 旧バージョンの場合では必要だった require() / import が、 新バージョンでも残ってると指摘してくれるようになります。

.eslintrc.cjs
module.exports = {
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended",
		"plugin:react/jsx-runtime",
	],
	"settings": {
		"react": {
			"version": "detect",
		},
	},
};

PropTypes を用いた型チェックを無効化する

React にはコンポーネントに型の定義を追加して、型チェックを行うことができる PropTypes という機能があります。 TypeScript の型チェックのようなものです。 ESLint では PropTypes による型チェックがデフォルトで有効になっています。 無効化したい場合は下記のように変更します。

.eslintrc.cjs
module.exports = {
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended",
	],
	"rules": {
		"react/prop-types": "off",
	},
	"settings": {
		"react": {
			"version": "detect",
		},
	},
};

参考サイト

関連記事

最近は jQuery を使用せずに Vue.js を使用されている方も多いのではないでしょうか。そこで Vue.js の使い方についてまとめてみます。誰かのお役に立てば幸いです。Vue.js とは?JavaScript のライブラリと言えば jQuery が有名です。jQuery はローレベルの API で構成されてい ...
最近の Web の開発では、webpack を使用することはもはや当たり前のような状況です。そこで改めてその使用方法をまとめてみたいと思います。今更かもしれませんが、誰かの参考になれば幸いです。webpack とは?近年の Web 開発では、サーバーサイド(PHP など)ではなく、クライアントサイド(JavaScrip ...
JavaScript は文法的にかなりフレキシブルな言語であり、コードが汚くなりがちです。キレイで読みやすいコードを保つために、JavaScript にも静的解析ツールを導入しましょう。ESLint とは?ESLint は、JavaScript の静的解析ツールです。JavaScript コードを実行する前に(つまり静 ...
近年の Web 開発では、サーバーサイド(PHP など)ではなく、クライアントサイド(JavaScript)で処理することが多くなりました。JavaScript の重要性が増えるに伴って、そのテストもまた重要になってきます。Jest とは?Jest は、Meta 社(旧:Facebook 社)製の JavaScript ...
最近の Web 界隈では、UX を高めるために、UI を JavaScript でガリガリ実装するというのが普通になってます。フロントエンドエンジニアなんていう職種が生まれるほど、この界隈は活発です。そこでフロントエンド開発でほぼ必須となるであろう Node.js と npm について少しまとめてみます。今更感がすごい ...

記事検索

最新記事

人気記事

RSSフィード

お知らせ

フィードバック

要望などあれば、お気軽にどーぞ。 不具合やバグを発見した場合も、連絡をいただけると助かります。

匿名でフィードバックする
匿名でフィードバックする

要望などあれば、お気軽にどーぞ。 不具合やバグを発見した場合も、連絡をいただけると助かります。

なお、このフォームから入力された内容について、管理者から返信はできませんので注意してください。 もし、管理者からの返信が必要であれば、X(Twitter) もしくは、お問い合わせより、お願いします。

  • フィードバックの送信が完了しました。