React の使い方
最近では JavaScript のライブラリとして React を使用して開発されている方も多いのではないでしょうか。 そこで React の使い方についてまとめてみます。 いまさら感がスゴイですが、誰かのお役に立てれば幸いです。
React とは?
React は、UI(ユーザインターフェース)をコンポーネントと呼ばれる部品を使って構築するための JavaScript ライブラリです。 Meta 社(旧:Facebook 社)製です。 大規模で複雑なアプリケーションを作成する際に React が採用されていることが多く、React について難しい印象を持たれている方も多いのではないでしょうか。 しかしながら、React そのもののコンセプトはそれほど難しいものではありません。
コンポーネント
Web システムの世界では、様々な理由から HTML や JavaScript といった、言語ごとの大きい縦の区切りでソースコードを分割するのが普通でした。 しかしその場合、UI 部品の「処理」と「見た目」がそれぞれ別々のファイルに記述されてしまうことになるため、 UI 部品を再利用することが少し困難でした。
React を使用すると、UI 部品の「処理」と「見た目」の両方を「コンポーネント」という単位で1つにまとめることが可能になります。 コンポーネントという単位でまとめることで、UI 部品として再利用することが容易になります。 また、開発を行う際にも、コンポーネントという単位で作業を分担することができるようになるため、 大人数での作業がしやすくなったりします。
では、実際にどうやってコンポーネントを作成するか見てみましょう。
下記の例を見てください。
これは、ボタンをただ表示するだけのコンポーネントになります。
React のコンポーネントは、JavaScript の関数として記述します。
関数の中にそのコンポーネントの「処理」を記載し、その「見た目」を return
で返します。
普通の JavaScript の関数との違いは return
でコンポーネントの見た目を返すかどうかぐらいでしかありません。
function MyButton() { // コンポーネントの「処理」をここに記述する // 例えば、ボタンの状態や、ボタンが押された時の処理などを記述する // コンポーネントの「見た目」を返す return ( <button>This is a button</button> ); }
え? JavaScript ファイルの中に HTML タグが直接書かれているように見える? これではシンタックスエラーになって動かないのではないかですって??? ...そうです。その通りです。 これは JSX と言いまして、JavaScript の中に HTML タグのようなマークアップを直接記述できるようになる拡張構文になります。 JSX の詳細については後述しますので、まずはコンポーネントの振舞いについて注目してください。
今度は上記の例で作成したコンポーネント「MyButton」を、別のコンポーネントの中で使用する方法を見てみましょう。
コンポーネントの中で、別のコンポーネントを使用するには、
return
で返すマークアップの中に、使用したいコンポーネントを HTML のタグと同様にマークアップの形式で記述します。
通常の HTML のタグと区別するために、コンポーネントの名前の先頭は常に大文字にする必要があるので注意してください。
このようにマークアップとして記述することで、好きな位置に好きなコンポーネントを埋め込むことができます。
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 を使用した例と比べてみてください。
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 を使用していますが、
他にも jsDelivr や cdnjs など、
npm パッケージを提供する CDN なら何でも使用することができます。
もちろん、このファイルをダウンロードして、自分で配信することもできます。
<!-- 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:概要)」を参考にしてください。
npm install --save-dev react react-dom
npm を使用してインストールした場合は、使用したいファイルで読み込む必要があります。
CommonJS の場合は require()
、ES Modules の場合は import
を使用して読み込みます。
// react パッケージの読み込み const React = require('react'); // react-dom パッケージの読み込み const ReactDOM = require('react-dom/client');
// 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)を使用するためのものといった感じでしょうか。
npm install --save-dev babel-loader @babel/preset-react
「babel-loader」パッケージと、「@babel/preset-react」パッケージがインストールできたら、 webpack の設定ファイルで、それらを使用するように設定します。
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
オブジェクトが使われている状態になってしまうからです。
// 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」パッケージの設定で、
runtime
に automatic
を指定します。
ちなみに旧バージョンを使用する場合は、classic
を指定します。
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
で読み込むかによって、
書き方に多少の違いがありますので注意してください。
// 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 />);
<!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 の設定ファイルを下記のように変更します。
extends
に plugin:react/recommended
を追加することで JSX が扱えるようになります。
また、settings.react.version
で React のバージョンを指定する必要があります。
detect
を指定すると使用されている React のバージョンを自動で設定してくれます。
現状では指定しないと Warning が表示されるようです。
将来的にはデフォルトが detect
になり、指定しなくても良くなるようです。
module.exports = { "extends": [ "eslint:recommended", "plugin:react/recommended", ], "settings": { "react": { "version": "detect", }, }, };
script タグで読み込んでいる場合
React を script
タグで読み込んでいる場合は、
ESLint からは React
オブジェクトと ReactDOM
オブジェクトが見つかりませんので、
globals
に追加してエラーにならないように設定します。
module.exports = { "globals": { "React": "readonly", "ReactDOM": "readonly", }, "extends": [ "eslint:recommended", "plugin:react/recommended", ], "settings": { "react": { "version": "detect", }, }, };
JSX の変換が新バージョンの場合
JSX の変換が新バージョンの場合は、extends
に plugin:react/jsx-runtime
を追加します。
旧バージョンの場合では必要だった require()
/ import
が、
新バージョンでも残ってると指摘してくれるようになります。
module.exports = {
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
],
"settings": {
"react": {
"version": "detect",
},
},
};
PropTypes を用いた型チェックを無効化する
React にはコンポーネントに型の定義を追加して、型チェックを行うことができる PropTypes という機能があります。 TypeScript の型チェックのようなものです。 ESLint では PropTypes による型チェックがデフォルトで有効になっています。 無効化したい場合は下記のように変更します。
module.exports = { "extends": [ "eslint:recommended", "plugin:react/recommended", ], "rules": { "react/prop-types": "off", }, "settings": { "react": { "version": "detect", }, }, };
参考サイト
- React
- クイックスタート – React
- react - npm
- react-dom - npm
- react-native - npm
- react-test-renderer - npm
- React DOMとReact Nativeの違い(2018)
- 結局、Reactとは何なのか | 岡山のWEB制作はKOMARI
- babel-loader - npm
- @babel/preset-react - npm
- 新しい JSX トランスフォーム – React Blog
- React17におけるJSXの新しい変換を理解する
- eslint-plugin-react - npm
- PropTypes を用いた型チェック – React