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

# はじめに

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

https://qiita.com/MichaelHashimoto/items/f3ad9f56081a40b9b788

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

# JSX

次のような記事を作りたいとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1223968/dc96b096-cfe8-3656-6a30-cc6f79ca360c.png)

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

```js
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を使って書くと、以下のようになります。

```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なので、ブラウザがあれば誰でも実行できます。
```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です。

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

```jsx
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の２つの状態を保持させています。また、このコンポーネントを使う側(親コンポーネント)がpropsに"title"というプロパティを与える前提でコードを書いているため、```{this.props.title}```というコードが登場します。

## 描画してみる

```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 {
            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クラスを継承したクラスのことを指します。
```jsx
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#を使ってきた私にとっては、非常に理解しやすかったのですが、どうやらあまり使われないようです。
というのも、関数コンポーネントというもう一つのコンポーネントを使ったほうが、シンプルで簡潔な構文となり、コードが読みやすくなるそうです。

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

クラスコンポーネントを関数コンポーネントに書き換えると次のようになります。
```jsx
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のラムダ式に相当します)。
無名関数を作るためには、関数式を使う方法と、アロー関数式という簡潔な構文を使う方法があります。

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

// アロー関数式
const square = (number) => {
  return number * number;
}
```
ただ "function(引数)" という形にするか、"(引数)=>" という形にするかという違いだけです。

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

# イベントハンドリング

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

以下では、onClickに関数自身を代入することで、ボタン押下時のイベントを設定しています。ボタンを押すと"Button clicked!"と表示されます。
```jsx
const HelloWorld = (props) => {
    const handleButtonClick = () => {
        alert("Button clicked!")
    }

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

propsを使って、親が子コンポーネントのイベントを設定することもできます。
```jsx
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 こちらの記事を参考にしてください。

# 最後に

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

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

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

## 参考文献

https://qiita.com/kenogi/items/4bb9032cc633e54211f2

https://qiita.com/omo_taku/items/18da0c020672a368f166

https://qiita.com/kotaro-caffeinism/items/cd84e4fc3aa90412474b