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

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


はじめに

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

なお、現時点では stage3。tc39/proposal-class-fields


tl;dl

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


それどういうやつ

class Sample { 
  x = 0; // public field 
  #x = 0; // private field 
 
  handleOnClick = (event) => { 
    // ... 
    this.x++; 
  } // public field 
} 
以上のように、簡単にプロパティを定義できる。


チェックのための環境

最低限の動作をするプロジェクトを作成してテストする。

コードはここに公開済み。
https://github.com/tomoyamachi/minimum-react-dom-check


各種ライブラリ

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

"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を入れる。

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


利用方法

$ git clone https://github.com/tomoyamachi/minimum-react-dom-check 
$ yarn  
$ yarn start 
http://localhost:8080 を開けばOK.

不要な再レンダリングが発生していると、 why-did-you-updateが教えてくれる。


検証内容

今回は、Publicなclass fieldsの動作確認とともに、バッドプラクティスと名高い、propsにbindや無名関数を直接いれちゃだめなやつも一緒にチェックした。

なお挙動確認のため、無理矢理stateを利用するなど、冗長になっている。


constructorでbindして渡す

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して渡す

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で即時関数として渡す

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で条件式を利用して渡す

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を利用

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されるので注意。

class Button extends React.PureComponent { 
    state = {type: this.props.type} 
 
    render() { 
        const {type, handleClick} = this.props; 
        return ( 
            <button onClick={() => handleClick(type)}> 
                {type} 
            </button>) 
    } 
}; 
そしてボタンを押してコンソールを確認する。



result.png


propsで直接bindして渡すpropsで即時関数として渡す が意味もなく再レンダリングされているのがわかる。

知識通りの挙動ではあるが、やはり手を動かして作ると実感が湧くのでいい。


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


constructorがなくなり、コードがすっきりする

一番わかり易いメリットはこれ。

特に、関数に対してbindしてプロパティに渡すをしなくてよくなるのは助かる。


stateなどがプロパティに過ぎないことが理解しやすい

本来プロパティはクラスの属性なので、constructorの中で定義すると違和感があった。それもなくなる。

たとえば、 this.func = this.func.bind(this) はプロパティに関数を代入する行為に過ぎないはずだが、それが分かりづらい。黒魔術感が強い。

JS初心者の頃、この記述の必要性がわからず、もやもやした。


まとめ

Private Class Fieldsの挙動もチェックしたけど、後日記事にしていくつもり。

Static Class Fieldsをガンガン利用していこう。

コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)