Reactの基礎【JSX編】

14 min read

Reactの基礎【JSX編】

React第2弾です。
今回の内容はJSXです。

ReactでHello World

最初はプログラミングの定番である一番簡単なプログラムである「Hello World」を表示してみましょう。
react_app¥publicに以下のようなreact_app.htmlを作成してください。

react_app.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React App</title>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
</head>
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script>
        let dom = document.querySelector("#root");
        let element = React.createElement(
            "p", {}, "Hello World"
        );
        ReactDOM.render(element, dom);
    </script>
</body>
</html>

http://localhost:3000/react_app.htmlにアクセスすると、以下のような画面が表示されます。

解説

以下のReactのスクリプトをCDNで読み込みます。

https://ja.reactjs.org/docs/cdn-links.html
  • 開発用CDN
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
  • 本番用CDN
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
  • Reactはタグを書き換える
    • <div id="root">Wait...</div>をReactを使って「Hello World」に置き換えています。
  • エレメントの作成
    • エレメント:HTMLタグをJavaScriptのオブジェクトとして扱えるようにしたもの。
    • React.createElement(タグ名, 属性、 中に組み込むもの);
  • レンダリングした表示の作成
    • 作成したエレメントはReactDOMというオブジェクトのrender関数でレンダリングします。
    • ReactDOM(エレメント, DOM);

表示の更新

Reactで画面表示ができたら、画面の表示を更新する簡単なプログラムを作成してみましょう。
react_app.htmlを以下のように書き換えます。

react_app.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React App</title>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <style>
        #root {
            cursor: pointer;
            font-size: 20px;
            background-color: aliceblue;
            padding: 10px 20px;
        }
    </style>
</head>
<body>
    <h1>React App</h1>
    <div id="root" onclick="count();">Wait...</div>
    <script>
        let counter = 0;
        let dom = document.querySelector("#root");
        count();

        function count() {
            counter++;
            let element = React.createElement(
                "p", {}, "count: " + counter
            );
            ReactDOM.render(element, dom);
        };
    </script>
</body>
</html>

色が変わっている部分をクリックすると、カウントが増えていきます。

divタグの領域をクリックすると、count関数が実行され、createElemntしてrenderするような処理をしています。Reactの表示更新の基礎は、更新したら仮想DOMのエレメントを作ってレンダリングするというものです。しかし、この例のように、毎回createElemntしてrenderするやり方はナンセンスです、次の記事で紹介しますが、コンポーネントという仕組みがあってもっとすっきりとした書き方ができます。

スクリプトの分離

このまま使用してもいいのですが、HTMLタグの中にReactのコードがあるのは管理しづらいですので、別ファイルに切り分けましょう。

react_app.html
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React App</title>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
</head>
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script src="script.js"></script>
</body>
</html>
script.js
let dom = document.querySelector("#root");
let element = React.createElement(
    "p", {}, "Hello React Application!"
);
ReactDOM.render(element, dom);

以下のように表示されたらファイルの分離成功です。

JSXの使用

前置きが長くなりましたが、JSXを使ってReactプログラムを書いていきましょう。

  • JSXとは..?
    • 文法拡張と呼ばれ、HTMLタグを直接JavaScriptのスクリプトに記述する仕組み。
    • Babelというライブラリを使用してコンパイルしている。

何はともあれ、実際にコードを書いてみましょう。

ライブラリの読み込み

JSXを使用するには、ライブラリを読み込ませる必要があります。react_appのheadタグに以下を追加してください。

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>

JSXサンプルプログラム

JSXは、HTMLファイルを直接Webブラウザで開いた場合、スクリプトファイルを別に分離させるとうまく動いてくれません。先ほどファイルを分離させましたが、一旦元に戻します。
react_app.htmlを以下のように記載します。

reacr_app.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React App</title>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");
        let el = (
            <div>
                <h2>JSX Sample</h2>
                <p>This is sample.</p>
            </div>
        );
        ReactDOM.render(el, dom);
    </script>
</body>
</html>

画面は以下のようになります。

  • <script type="text/babel">
    • scriptタグの中身をBabelを使用してコンパイルする。
    • JSXを使用するときはtype="text/babel"を指定する。
  • JSXがrenderできるのは1エレメントのみである。
    • h2タグとpタグをまとめたdivタグを親とした1つのエレメントのみをrenderできる。

JSXでの値の埋め込み

JSXではタグをそのまま表示するだけでなく、値を埋め込むことができます。
値の埋め込みは、以下のように書きます(body部のみ記載)。

react_app.html
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");

        let title = "タイトル"
        let message = "Reactメッセージ"

        let el = (
            <div>
                <h2>{ title }</h2>
                <p>{ message }</p>
            </div>
        );
        ReactDOM.render(el, dom);
    </script>
</body>
</html>

画面は以下のようになります。

  • { XXXX }で指定した変数の値がタグの中に埋め込まれます。
  • 属性への埋め込みも可能である。
    • 例:<a href={ link }>リンクはこちらから</a>

JSXでのStyleの設定

値の埋め込みを利用し、JSXでStyleの指定が可能です。
以下のように書きます(body部のみ記載)。

react_app.html
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");

        let title = "タイトル"
        let message = "Reactメッセージ"

        const msgStyle = {
            fontSize: "32px",
            color: "red"
        }

        let el = (
            <div>
                <h2>{ title }</h2>
                <p style={msgStyle}>{ message }</p>
            </div>
        );
        ReactDOM.render(el, dom);
    </script>
</body>

画面は以下のようになります。

  • JSXでは、いつものCSSでの記法ではエラーとなります。
    • ケバブケースキャメルケースで記載しなければなりません。

JSXでの関数

JSXでは関数を作成できます。
以下のように書きます(body部のみ記載)。

react_app.html
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");

        let message = function(msg, size, color) {
            const msgStyle = {
                fontSize: size,
                color: color
            };
            return <p style={ msgStyle }>{ msg }</p>
        }

        let el = (
            <div>
                { message("message1", 30, "red") }
                { message("message2", 20, "blue") }
                { message("message3", 10, "green") }
            </div>
        );
        ReactDOM.render(el, dom);
    </script>
</body>

画面は以下のようになります。

JSXでの条件分岐

JSXでは条件分岐ができます。
以下のように書きます(body部のみ記載)。

react_app.html
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");

        let message = function(msg, size, color) {
            const msgStyle = {
                fontSize: size,
                color: color
            };
            return <p style={ msgStyle }>{ msg }</p>
        }

        let msg1Flg = true;
        let msg2Flg = false;

        let el = (
            <div>
                { msg1Flg && message("message1", 30, "red") }
                { msg2Flg && message("message2", 20, "blue") }
            </div>
        );
        ReactDOM.render(el, dom);
    </script>
</body>

画面は以下のようになります。

  • { 真偽値 && ...JSXの記述... }
    • 真偽値がtrueの場合、JSXの記述が有効となり、画面に表示されます。
    • 真偽値がfalseの場合、JSXの記述が無効となり、画面に表示されなくなります。
  • 三項演算子も使用可能。
    • 例:{ 真偽値 ? ...trueの場合のJSXの記述... ? ...falseの場合のJSXの記述... }

JSXでの配列と辞書型(キー・バリュー)

JSXでは配列と辞書型を使用できます。
以下のように書きます(body部のみ記載)。

react_app.html
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");

        const listData = [
            <li>apple</li>,
            <li>banana</li>,
            <li>melon</li>,
            <li>orange</li>
        ];

        const mapData = [
            {
                "name": "Taro",
                "mail": "taro@xxx.com",
                "age": 20
            },
            {
                "name": "Hanako",
                "mail": "hanako@xxx.com",
                "age": 19
            },
            {
                "name": "Nobita",
                "mail": "nobita@xxx.com",
                "age": 12
            }
        ]

        let el = (
            <div>
                <ul>{ listData }</ul>

                <table>
                    <tr>
                        <th>name</th>
                        <th>mail</th>
                        <th>age</th>
                    </tr>
                {mapData.map((value) => (
                    <tr>
                        <td>{ value.name }</td>
                        <td>{ value.mail }</td>
                        <td>{ value.age }</td>
                    </tr>
                ))}
                </table>
            </div>
        );
        ReactDOM.render(el, dom);
    </script>
</body>

画面は以下のようになります。

  • 配列.map((value) => 新しい要素)
    • mapでは、valueに配列の要素が順番に1つずつ渡されていきます。
    • valueに渡された要素が=>以降で記載された処理によって新しい戻り値を返します。

今回の例では、mapによって以下のように配列のデータが変換されています。

  • 変換前
const mapData = [
    {
        "name": "Taro",
        "mail": "taro@xxx.com",
        "age": 20
    },
    {
        "name": "Hanako",
        "mail": "hanako@xxx.com",
        "age": 19
    },
    {
        "name": "Nobita",
        "mail": "nobita@xxx.com",
        "age": 12
    }
]
  • 変換後
const mapData = [
    {
        <tr>
            <td>Taro</td>
            <td>taro@xxx.com</td>
            <td>20</td>
        </tr>
    },
    {
        <tr>
            <td>Hanako</td>
            <td>hanako@xxx.com</td>
            <td>19</td>
        </tr>
    },
    {
        <tr>
            <td>Nobita</td>
            <td>nobita@xxx.com</td>
            <td>12</td>
        </tr>
    }
]

JSXでの表示の更新

JSXを使い、画面に表示することはできました。それでは最後に表示の更新です。今回は入力フォームを使用して、画面の再描画をしていきます。
以下のように書きます(body部のみ記載)。

react_app.html
<body>
    <h1>React App</h1>
    <div id="root">Wait...</div>
    <script type="text/babel">
        let dom = document.querySelector("#root");

        let message = "お名前を入力してください";
        let inputtedName = "";

        let change = (e) => {
            inputtedName = e.target.value;
            message = "こんにちは、" + inputtedName + "さん!";
        }

        let action = (e) => {
            let el = (
                <div>
                    <p>{ message }</p>
                    <div>
                        <input type="text" id="input" onChange={ change } />
                        <button onClick={ action }>Click</button>
                    </div>
                </div>
            );
            ReactDOM.render(el, dom);
        };

        action();
    </script>
</body>

画面は以下のようになります。

  • HTMLのタグは必ず/>で閉じる。
  • let change = (e) => XXX
    • 引数にイベントeを受け取ることができる。
    • e.target.value;でイベントが発生したエレメント(入力フォームのチェンジイベント)のvalueを取得しています。

まとめ

この記事では、JSXについてまとめてみました。JSXは、HTMLのタグとは微my方に違った点があり、値の埋め込みや条件分岐、関数などが使用できます。ただし、今回の内容は基礎的な内容でもっと応用した使い方がありますので、基礎をしっかり固めていきましょう。