Reactのコードを大幅に省略できるClassFieldsの挙動をチェック

# はじめに
ES2019で正式採用になるであろうClassFieldsの挙動について、よく考えず使っていたので、今更ではあるが、どのような動作をするかチェックした。

なお、現時点では stage3。[tc39/proposal-class-fields](https://github.com/tc39/proposal-class-fields)

# tl;dl
- class fieldsはめっちゃ便利なのでどんどん利用していこう
- 自分で手を動かすと理解が深まるよね

# それどういうやつ

```react
class Sample {
  x = 0; // public field
  #x = 0; // private field
  
  handleOnClick = (event) => {
    // ...
    this.x++;
  } // public field
}
```

以上のように、簡単にプロパティを定義できる。

# チェックのための環境

最低限の動作をするプロジェクトを作成してテストする。
コードはここに公開済み。
https://github.com/tomoyamachi/minimum-react-dom-check


# 各種ライブラリ

基本ツールのバージョン情報は以下の通り。

```json
    "react": "16.6.3",
    "react-dom": "16.6.3"
    "babel-core": "^6.26.3",
    "webpack": "^4.28.2",
    "webpack-dev-server": "^3.1.14",
    "why-did-you-update": "^1.0.6"
```

これにビルド時に必要なbabelのpreset/pluginを追加する。
今回は、class-properties用のpluginを入れる。

```json
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
```

# 利用方法

```shell
$ git clone https://github.com/tomoyamachi/minimum-react-dom-check
$ yarn 
$ yarn start
```

http://localhost:8080 を開けばOK.

不要な再レンダリングが発生していると、 [why-did-you-update](https://github.com/maicki/why-did-you-update)が教えてくれる。

# 検証内容

今回は、Publicなclass fieldsの動作確認とともに、バッドプラクティスと名高い、propsにbindや無名関数を直接いれちゃだめなやつも一緒にチェックした。
なお挙動確認のため、無理矢理stateを利用するなど、冗長になっている。

## constructorでbindして渡す
```react
class ButtonWithBind extends React.Component {
    constructor(props) {
        super(props);
        this.state = {type: "WithBind"}
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick(message) {
        console.log(message, this.props.count)
        this.props.countUp();
    }

    render() {
        const {type} = this.state;
        return <Button type={type} key={type} handleClick={this.handleClick}/>;
    }
}
```

## propsで直接bindして渡す

```react
class ButtonWithoutBind extends React.Component {
    constructor(props) {
        super(props);
        this.state = {type: "WithoutBind"}
    }

    handleClick(message) {
        console.log(message, this.props.count)
        this.props.countUp();
    }

    render() {
        const {type} = this.state;
        return <Button type={type} key={type} handleClick={this.handleClick.bind(this)}/>;
    }
}
```

## propsで即時関数として渡す
```react
class ButtonDirectCall extends React.Component {
    constructor(props) {
        super(props);
        this.state = {type: "DirectCall"}
    }

    handleClick(message) {
        console.log(message, this.props.count)
        this.props.countUp();
    }

    render() {
        const {type} = this.state;
        return <Button type={type} key={type} handleClick={(message) => this.handleClick(message)}/>;
    }
}
```
## propsで条件式を利用して渡す

```react
class ButtonCondition extends React.Component {
    constructor(props) {
        super(props);
        this.state = {type: "Condition"}
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick(message) {
        console.log(message, this.props.count)
        this.props.countUp();
    }

    render() {
        const {type} = this.state;
        return <Button type={type} key={type} handleClick={true && this.handleClick}/>;
    }
}
```
## Class Fieldsを利用

```react
class ButtonClassState extends React.Component {
    state = {type: "ClassState"}
    handleClick = (message) => {
        console.log(message, this.props.count)
        this.props.countUp();
    }

    render() {
        const {type} = this.state;
        return <Button type={type} key={type} handleClick={this.handleClick}/>;
    }
}
```



## Buttonコンポーネントの作成

PureComponentにしないと、全パターンでre-renderされるので注意。

```react
class Button extends React.PureComponent {
    state = {type: this.props.type}

    render() {
        const {type, handleClick} = this.props;
        return (
            <button onClick={() => handleClick(type)}>
                {type}
            </button>)
    }
};
```

そしてボタンを押してコンソールを確認する。

<img width="1661" alt="result.png" src="https://qiita-image-store.s3.amazonaws.com/0/14275/18365eb2-64a4-cc6f-b603-7c766f8c98d9.png">

`propsで直接bindして渡す` と `propsで即時関数として渡す` が意味もなく再レンダリングされているのがわかる。
知識通りの挙動ではあるが、やはり手を動かして作ると実感が湧くのでいい。


# 結果 : ReactでClassFieldsを利用すると...

## constructorがなくなり、コードがすっきりする
一番わかり易いメリットはこれ。
特に、関数に対してbindしてプロパティに渡すをしなくてよくなるのは助かる。

## stateなどがプロパティに過ぎないことが理解しやすい
本来プロパティはクラスの属性なので、constructorの中で定義すると違和感があった。それもなくなる。
たとえば、 `this.func = this.func.bind(this)` はプロパティに関数を代入する行為に過ぎないはずだが、それが分かりづらい。黒魔術感が強い。
JS初心者の頃、この記述の必要性がわからず、もやもやした。

# まとめ
Private Class Fieldsの挙動もチェックしたけど、後日記事にしていくつもり。
Static Class Fieldsをガンガン利用していこう。