この日記は私的なものであり所属会社の見解とは無関係です。 GitHub: takahashikzn

React-0.13でpropTypesを違和感なく記述する

最近、とある業務システムの一部となるリッチ画面をReactで開発してます。


Reactは良く出来ていると思います。
できるだけステートレスにすることで安全なコードを記述するという思想は僕の好みです。


Fluxも同じく良い。『処理の流れは一方向。何も考えずにイベントを処理し続ければ良い』という、ある種のストリーミング的な発想により、非常に見通しの良い構成を実現できます。

Fluxのフレームワークは乱立気味ですが、色々比較した結果、僕はrefluxを選びました。
そんなに多機能じゃないので自分で魔改造しやすいところがナイス。

React-0.13から使えるclass構文

最近リリースされたreact-0.13からES6のclass構文を使えるようになりました。

reactに付属するJSXTranformerでパースできるようになったとは言え、
イマドキReactを使うような人は当然Babelでトランスパイルしてますよね?

え?CoffeeScript?TypeScript?本日の日記はここで終わりです。
読んで頂きありがとうございました。



...だから、classどころではなくES6のフル機能を使えるわけです。


propTypesの宣言方法

さて、React-0.13のリリースノートでは次のように書かれています。

ES7+ Property Initializers

Wait, assigning to properties seems like a very imperative way of defining classes! You're right, however, we designed it this way because it's idiomatic. We fully expect a more declarative syntax for property initialization to arrive in future version of JavaScript. It might look something like this:

// Future Version
export class Counter extends React.Component {
  static propTypes = { initialCount: React.PropTypes.number };
  static defaultProps = { initialCount: 0 };
  state = { count: this.props.initialCount };
  tick() {
    this.setState({ count: this.state.count + 1 });
  }
  render() {
    return (
      <div onClick={this.tick.bind(this)}>
        Clicks: {this.state.count}
      </div>
    );
  }
}

This was inspired by TypeScript's property initializers.

要約すると、

propTypesは意味的にコンポーネントクラスの静的メンバとして宣言できるべきだが、ES6では無理。ES7では以下のように書けるようになるはず。それまで我慢しろ

とのことです。

だから、JSXTransformerを使う限りは、

export class Counter extends React.Component {
  constructor(props) { ... }

  tick() { ... }
  render() { ... }
}

// 静的メンバーの宣言
Counter.propTypes = { initialCount: React.PropTypes.number };
Counter.defaultProps = { initialCount: 0 };

のように書く必要があります。
クラスのメンバーにも関わらず、クラス構文の外で定義することになり何ともカッコ悪い。


1つの式で表現するならば

// 強引に1つの式で定義
export const Counter = Object.defineProperties(
    class extends React.Component { // 無名クラス
        constructor(props) { ... }

        tick() { ... }
        render() { ...}
    }, 
    {
        propTypes: {
            value: { initialCount: React.PropTypes.number }
        },
        defaultProps: {
            value: { initialCount: 0 }
        }
    }
);

などと書くことになりますが、個人的にはイマイチ。

しかしBabelなら

静的メンバーを普通に宣言できます。次の通り。

export class Counter extends React.Component {

  // 静的メンバーの宣言
  static get propTypes() { return { initialCount: React.PropTypes.number }; }
  static get defaultProps() { return  { initialCount: 0 }; }

  constructor(props) {
    ...
  }
  tick() {
    ...
  }
  render() {
    ...
  }
}

これで問題なく動きます。Reactのソースを読めばわかりますが、Reactの内部では単に

componentClass.propTypes

とやっているだけ*1なので、当然のように動く。

記述量が増えるのはやむを得ませんが、見た目には違和感がなく自然な表記です。


そりゃもちろんES7のように書けるに越したことはありませんが、
個人的には、もうずっとこれでいいんじゃね?と思ってます。

*1:ReactElementValidator.jsのcheckPropTypesを参照