0
0

JSX・クラスコンポーネントと関数コンポーネント [5日間でReactの基礎を習得したい 2/5日目]

Posted at

はじめに

5日間でReactの基礎を習得する試みの2日目です。2日目は、Reactでよく使われるJSXの記法、クラスコンポーネントと関数コンポーネントについて学びます。

私はC#やPythonを仕事で使っているため、オブジェクト指向の言語的な考え方や、Pythonでの例えを使って理解を進めます。同じような境遇の方の理解の助けになれば幸いです。

JSX

次のような記事を作りたいとします。
image.png

この記事を作るために、ただのJavaScriptの構文でReactのHelloWorldクラスコンポーネントを作ると、以下になります。

class HelloWorld extends React.Component {
    render() {
        return React.createElement('div', null,
            React.createElement('h1', null, 'Hello World'),
            React.createElement('h2', null, 'Introduction to HelloWorld'),
            React.createElement('p', null, 'Hello Worldプログラムは、新しいプログラミング言語を習得するときの、最初のプログラムです。'),
            React.createElement('h2', null, 'Why HelloWorld?'),
            React.createElement('p', null, 'Hello Worldはシンプルなため、最初に言語の構造や特徴を理解するのに役立ちます。')
      );
    }
}

React.createElementを使って書くと、div, h1, h2, pタグの関係や内容が分かりづらくなってしまいます。
JavaScriptでも、HTMLのようにタグを使えれば、もっと見やすいコードになりそうです。

そこで、JSXを使う

JSXとはJavaScriptの拡張で、JavaScript内にHTMLのタグなどのマークアップが使えるようにしてくれます。

さきほどのコンポーネントをJSXを使って書くと、以下のようになります。

class HelloWorld extends React.Component {
    render() {
        return (
            <div>
                <h1>Hello World</h1>
                <h2>Introduction to HelloWorld</h2>
                <p>Hello Worldプログラムは、新しいプログラミング言語を習得するときの、最初のプログラムです。</p>
                <h2>Why HelloWorld?</h2>
                <p>Hello Worldはシンプルなため、最初に言語の構造や特徴を理解するのに役立ちます。</p>
            </div>
        );
    }
}

このコンポーネントを使って描画するコードが以下です。コンポーネントの内容が非常に見やすくなりました。
HTMLなので、ブラウザがあれば誰でも実行できます。

test.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>React Simple Example</title>
</head>
<body>
    <div id="root"></div>
    <!-- ReactとReactDOMのライブラリを読み込む -->
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <!-- Babelライブラリを読み込む(ブラウザでJSXを解釈するために必要) -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    
    <!-- JSXを使用してJavaScriptを書く-->
    <script type="text/babel">
        'use strict';

        class HelloWorld extends React.Component {
            render() {
                return (
                    <div>
                        <h1>Hello World</h1>
                        <h2>Introduction to HelloWorld</h2>
                        <p>Hello Worldプログラムは新しいプログラミング言語を習得するときの最初のプログラムです</p>
                        <h2>Why HelloWorld?</h2>
                        <p>Hello Worldはシンプルなため最初に言語の構造や特徴を理解するのに役立ちます</p>
                    </div>
                );
            }
        }

        ReactDOM.createRoot(document.getElementById('root'))
            .render(<HelloWorld />);
    </script>
</body>
</html>

(補足)Babel

上のtest.htmlでは、Babelライブラリを読み込んでいます。これは、JSXをJSに変換してくれるライブラリです。(つまり、HTMLっぽいマークアップの部分を、React.CreateElementに変換してくれる)
Babelについては https://qiita.com/micropig3402/items/064394428791144f5488 の記事がわかりやすいです。

propsとstate

コンポーネントにおいて、重要なのがpropsとstateです。

以下のクラスコンポーネントのコンストラクタを見てください。

class HelloWorld extends React.Component {
    constructor(props) {
        super(props);
        
        this.state = {
            helloValue: 0,
            worldValue: 2,
        };
    }

    render() {
        return (
            <div>
                <h1>Hello, World!</h1>
                <p>Title: {this.props.title}</p>
                <p>Hello Value : {this.state.helloValue}</p>
                <p>World Value : {this.state.worldValue}</p>
            </div>
        );
    }
}

props: React.Componentクラスが持つメンバ変数で、プロパティのこと。コンストラクタの引数として使う。読み取り専用で、コンポーネント内では変更ができない。

state: React.Componentクラスが持つメンバ変数で、辞書のように状態を保持するオブジェクト。コンポーネント内からも変更が可能で、値が変わると自動的に再描画される。

上記のコードでは、stateにhelloValueとworldValueの2つの状態を保持させています。また、このコンポーネントを使う側(親コンポーネント)がpropsに"title"というプロパティを与える前提でコードを書いているため、{this.props.title}というコードが登場します。

描画してみる

test.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>React Simple Example</title>
</head>
<body>
    <div id="root"></div>
    <!-- ReactとReactDOMのライブラリを読み込む -->
    <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <!-- Babelライブラリを読み込む(ブラウザでJSXを解釈するために必要) -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    
    <!-- JSXを使用してJavaScriptを書く-->
    <script type="text/babel">
        'use strict';

        class HelloWorld extends React.Component {
            constructor(props) {
                super(props);
                
                this.state = {
                    helloValue: 0,
                    worldValue: 2,
                };
            }

            
            render() {
                return (
                    <div>
                        <h1>Hello, World!</h1>
                        <p>Title: {this.props.title}</p>
                        <p>Hello Value : {this.state.helloValue}</p>
                        <p>World Value : {this.state.worldValue}</p>
                    </div>
                );
            }
        }

        ReactDOM.createRoot(document.getElementById('root'))
            .render(<HelloWorld title="Hello Title"/>);
    </script>
</body>
</html>

.render(<HelloWorld title="Hello Title"/>)のところがコンポーネントからReact要素を作り出している部分です。<コンポーネント名 与えたいプロパティ名1="" 与えたいプロパティ名2=""...>のように記載することで、コンストラクタの引数であるpropsに値を設定できます。(今回の場合はprops.titleに当たります)

クラスコンポーネントと関数コンポーネント

クラスコンポーネント[あまり使われない]

ここまで、クラスコンポーネントを使って説明してきました。
クラスコンポーネントとは、React.Componentクラスを継承したクラスのことを指します。

class HelloWorld extends React.Component {
    constructor(props) {
        super(props);
        
        this.state = {
            helloValue: 0,
            worldValue: 2,
        };
    }
    
    render() {
        return (
            <div>
                <h1>Hello, World!</h1>
                <p>Title: {this.props.title}</p>
                <p>Hello Value : {this.state.helloValue}</p>
                <p>World Value : {this.state.worldValue}</p>
            </div>
        );
    }
}

C#を使ってきた私にとっては、非常に理解しやすかったのですが、どうやらあまり使われないようです。
というのも、関数コンポーネントというもう一つのコンポーネントを使ったほうが、シンプルで簡潔な構文となり、コードが読みやすくなるそうです。

関数コンポーネント[こっちを使う]

クラスコンポーネントを関数コンポーネントに書き換えると次のようになります。

const HelloWorld = (props) => {
    // useStateを使ってstateを定義する
    const [helloValue, setHelloValue] = React.useState(0);
    const [worldValue, setWorldValue] = React.useState(2);

    return (
        <div>
            <h1>Hello, World!</h1>
            <p>Title: {props.title}</p>
            <p>Hello Value : {helloValue}</p>
            <p>World Value : {worldValue}</p>
        </div>
    );
}

引数にpropsを取り、返り値にReact要素を持つアロー関数式を書けば、関数コンポーネントとなります。

関数なので、メンバ変数であるstateを保持することができません。その代替え手段として、フックと呼ばれるもののが用意されており、ここではuseStateを使っています。ここは次回勉強します。

(前提知識) 関数式

JavaScriptでは、無名関数が使用できます(Pythonのラムダ式に相当します)。
無名関数を作るためには、関数式を使う方法と、アロー関数式という簡潔な構文を使う方法があります。

// 関数式
const square = function (number) {
  return number * number;
}

// アロー関数式
const square = (number) => {
  return number * number;
}

ただ "function(引数)" という形にするか、"(引数)=>" という形にするかという違いだけです。

関数コンポーネントの宣言では、アロー関数式がよく使われます。コンポーネントの引数であるpropsを使った、(props) => {return React要素} の形が基本となるわけです。

イベントハンドリング

コンポーネントでイベントを設定することもできます。

以下では、onClickに関数自身を代入することで、ボタン押下時のイベントを設定しています。ボタンを押すと"Button clicked!"と表示されます。

const HelloWorld = (props) => {
    const handleButtonClick = () => {
        alert("Button clicked!")
    }

    return (
        <button onClick={handleButtonClick}>ボタン</button>
    );
}

propsを使って、親が子コンポーネントのイベントを設定することもできます。

const HelloWorld = (props) => {
    // propsにonButtonClickというプロパティが渡される前提で実装
    return (
        <button onClick={props.onButtonClick}>ボタン</button>
    );
}

const handleButtonClick = () => {
    alert("Button clicked!")
}

// HelloWorldコンポーネントのpropsのonButtonClickに、handleButtonClickを設定。
ReactDOM.createRoot(document.getElementById('root'))
    .render(<HelloWorld onButtonClick={handleButtonClick} />);

他にも色々なイベントハンドラが使えます。 https://qiita.com/P-man_Brown/items/bc7606504d64da42e13e こちらの記事を参考にしてください。

最後に

なじみやすかったクラスコンポーネントから理解し、その後に関数コンポーネントへの移行方法を考えたことで、コンポーネントがかなり理解できたように思います。

次回はフックについて学びます。

何か間違いがあれば、是非コメントを頂けると助かります!

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0