React: ES6クラス構文のデフォルトの小道具

作成日 2015年04月22日  ·  40コメント  ·  ソース: facebook/react

ES6サポートの発表によると:

クラスの状態を指定する慣用的な方法は、単純なインスタンスプロパティを使用することです。 同様に、getDefaultPropsとpropTypesは、実際にはコンストラクターの単なるプロパティです。

これは私には非常に理にかなっていますが、再考する価値のある小さな矛盾に気づきました。

元の.createClass構文を使用する場合、 getDefaultPropsによって返される値は、コンストラクターだけでなく、コンポーネントライフサイクルの他のポイントでも使用されているようです。 たとえば、 componentWillReceiveProps(props)に送信されるものを調べると、デフォルトの小道具が適用されていることがわかります。

これは、ES6クラス構文を使用する場合には当てはまらないようです。つまり、コードを複製する必要があります。 これが私が意味することの例です:

class Control extends React.Component {

  constructor(props) {
    props.value = props.value || '';
    super(props);
  }

  // ...

  componentWillReceiveProps(props) {
    props.value = props.value || '';
    // Do something with props...
  }

}

ご覧のとおり、 props.value = props.value || ''という式を複製しています。 デフォルトが複数ある場合は、明らかに重複が多くなります。

使用する場合は.createClass方法を、私は返すことができます{value: ''}からgetDefaultProps方法を、これが働くだろう、と私は一度だけそれをしなければならないと思います。

不必要な重複を避けるために、このメソッドを復元することは理にかなっていますか? 私が気付いていない別の、もっとReactのようなアプローチはありますか?

最も参考になるコメント

そのとおりです。 代わりに、次のように記述します。

class Control extends React.Component {

  // ...

  componentWillReceiveProps(props) {
    // Do something with props...
  }

}
Control.defaultProps = {value: ''};

それはあなたのために働きますか?

全てのコメント40件

componentWillReceivePropsが呼び出されたときに、デフォルトの小道具がすでにマージされている必要があります。

componentWillReceivePropsが呼び出されたときに、デフォルトの小道具がすでにマージされている必要があります。

私の知る限り、ES6クラス構文を使用する場合、 getDefaultPropsが呼び出されることはありません。

そのとおりです。 代わりに、次のように記述します。

class Control extends React.Component {

  // ...

  componentWillReceiveProps(props) {
    // Do something with props...
  }

}
Control.defaultProps = {value: ''};

それはあなたのために働きますか?

ああ、すみません、私は今ドキュメントでそれを見ます。 ありがとう!

私はGoogle検索からここにたどり着き、コードをカプセル化するためにclassを好むので、デフォルトの小道具は次のように計算されたプロパティを使用して設定できます。

import React, {Component, PropTypes} from 'react'
class DefaultPropsExample extends Component {
  static defaultProps = {
    ...Component.defaultProps,
    instructions: 'Usage instructions not provided.',
  }
}

@jhabdasあなたが与えたのはES2015構文ではないと思います。 静的な小道具を使用すると、バベルは予期しないトークンをスローしますが、es2015で私のように働く人のために、ここに機能するものがあります。

import React from 'react';
export default class extends React.Component {

  static get defaultProps() {
    return {
      // stuff you want :)
    }
  }

}

アップデート

@zpaoのリンクをインストールした後、静的プロパティを使用できます...

@ Gopikrishna19クラスプロパティの提案を実装する別のbabelプラグインを有効にする必要があります: http ://babeljs.io/docs/plugins/transform-class-properties/

@zpao Ooh! 今日の別の新しいもの:)それを試してみます、どうもありがとう!

@ Gopikrishna19私は実際にあなたが投稿したコードスニペットが好きですb / cデフォルトの小道具を初期化する前にいくつかの前処理を行うことができます。 言及してくれてありがとう。

これは機能しているようで、私の意見ではよりエレガントです。

....

 static defaultProps = {
      //someDefaultProps
  };

  constructor(props, defaultProps) {
    super(props, defaultProps);
  }

....

@ fxhereng2番目の引数はcontext用に予約されているため、将来のリリースで機能しなくなる可能性があるため、カスタムの意味でオーバーライドすることは避けます。

OK @gaearonデフォルトの小道具を設定する最良の方法は何ですか?

ありがとう、

これを行うための推奨される方法は何ですか?

実験的な変換http://babeljs.io/docs/plugins/transform-class-properties/を使用する場合は、 static defaultProps = {...};使用できます。 コンストラクターを変更する必要はありません。 それ以外の場合は、外部に割り当てる必要があります。

class X extends React.Component {
}
X.defaultProps = {...};

また..

class X extends React.Component {
  props = {
    ...
  }
}

@efernandesngこれはサポートされているパターンではありません。 defaultPropsように動作せず、 this.propsを変更します。これは実行しないでください。

defaultPropsを親クラスでインスタンス化して、それらの小道具を内の別の子クラスに渡すことができないようです。

それを行うための標準的なes6の方法はありますか? ここにあるすべての方法が私にはうまくいきません。

defaultPropsを親クラスでインスタンス化して、それらの小道具を内の別の子クラスに渡すことができないようです。

どういう意味かわかりません。 例を挙げていただけますか?

もちろん、ごめんなさい。

コンポーネントは次のとおりです。

import React, 
{
  Component,
  PropTypes
}                     from 'react';
import { TimerView }  from './TimerView'

class Timer extends Component {
  constructor(props) {
    super(props);
  }

  componentWillReceiveProps(props) {
    console.log('Will receive props')
  }

  render() {
    console.log("Timer loaded")

    return (
      <TimerView {...props} />
    )
  }
}

Timer.propTypes = {
  status: PropTypes.string.isRequired,
};

Timer.defaultProps = {
  status: "This is the Timer",
};

export default Timer;

webpack-dev-serverを実行すると、次のエラーが発生します。
Uncaught ReferenceError: props is not defined

私が間違っていることがあるに違いありません...

propsは、 render()メソッドのバインドされていない変数です。 <TimerView {...this.props} />である必要があります。

ああ、私の。
私はこれを完全に逃しました。 クラスと同じくらいステートレスコンポーネントを使用しているので、これで混乱しただけだと思います。

ありがとうございます。

問題ありません@jeanmichelcote! それは起こります:)

defaultPropsを定義するために他の小道具にアクセスすることはアンチパターンと見なされますか?

class Comp extends from React.Component {
  static propTypes: {
    num: React.PropTypes.number.isRequired,
    action: React.PropTypes.func,
  };

  static defaultProps: {
    action: () => console.log(this.props.num), // "this" is invalid in static context
  };

  render() {
    return (
      <button onClick={this.props.action}>
        {`Log #${this.props.num}`}
      </button>
    );
  }
}

@romulofは、静的メソッドからインスタンス変数を参照しようとしているようです。 どのthisについて話しているのかを判断する方法がないため、これを行うことはできません。 定義上、静的なものは常にインスタンスのコンテキストの外に存在します。

@romulofこれはすべてのオブジェクト指向言語に共通です。 太い矢印の構文は、それが定義されているコンテキストにバインドされます。多分あなたは使用してみることができます

static defaultProps: {
    action: function() {
        console.log(this.props.num), // "this" depends on the context where it is run
    }
};

@sbussard :その通りです。

私の質問は、静的オブジェクトとして実装されているdefaultPropsについてです。
たぶん、コンストラクターによって呼び出される関数にすることができます。

最適化コンパイラが呼び出しサイトでインライン化できるように、意図的にクラスの外にあります。

それで、最終的な答えは何ですか?

@gaearonあなたはそれについて言及しました

最適化コンパイラが呼び出しサイトでインライン化できるように、意図的にクラスの外にあります。

しかし、それは「クラスインスタンスフィールド」や「クラス静的フィールド」を使用するときに最適化できないことを意味しますか? どのアプローチが好ましいのか、そしてその理由を理解しようとしていると思います。

それで、最終的な答えは何ですか?

ES6に固執する場合は、下部に割り当てます。

class MyComponent extends Component { /* ... */ }
MyComponent.defaultProps = { /* ... */ };

Create React Appを使用している場合、または実験的な構文に慣れていて、クラスプロパティ変換を有効にしている場合は、次の操作を実行できます。

class MyComponent extends Component {
  static defaultProps = { /* ... */ };
  /* ... */
}

これらのアプローチは完全に同等です。 デコレータも使用している場合は、これらの変換を組み合わせた奇妙なバグがある可能性があることに注意してください。 したがって、クラスプロパティと一緒にデコレータを使用することはお勧めしません。

これがお役に立てば幸いです。

しかし、それは「クラスインスタンスフィールド」や「クラス静的フィールド」を使用するときに最適化できないことを意味しますか? どのアプローチが好ましいのか、そしてその理由を理解しようとしていると思います。

最後に割り当てることとクラスプロパティを使用することの間に違いはありません。 クラスプロパティは割り当てに脱糖します。 Babel WebサイトのREPLを使用して、どのコードがコンパイルされるかを確認してください。

@romulofが話しているのと同じ問題に興味があります。 もちろん、 static defaultPropsを使用してデフォルトのプロパティを定義できますが、コンテキストを使用したい場合はどうすればよいですか?

なぜこれが便利なのですか?

titleonSubmit小道具を持つ汎用モーダルコンポーネントがあります。 同じ小道具で、アプリのまったく異なる部分からモーダルを使用したい場合があります。 titleこれは問題なく機能します。

class CreateUserModal extends Modal {
  static defaultProps = { title: 'Create a new user' }
}

ただし、 onSubmitハンドラーは、たまたままともなコードのチャンクであり、reduxの接続から入力された小道具を使用するため、コンテキストが必要です。 現在、コンテキストを使用して親クラスの小道具を設定することはできないため、このコードを抽象化する方法はありません。

私がやろうとしているのは、実際にはアンチパターンではない(または少なくともそうではないと思う)ので、これを行う別の方法があるのだろうか?

私は私が次のようなことをすることができることを望みました

class CreateUserModal extends Modal {
  constructor (props) {
    super({
      title: 'Create a new user',
      onSubmit: () => {
        // do a load of stuff using props
      }
    })
  }
}

しかし、それは機能しません。

@roberttodあなたはあなたの問題の解決策を見つけましたか? ありがとう

フォローアップの質問をしたいのですが、
create reactアプリ(react-scripts v1.0.12)を使用している場合、初期状態を次のように定義しても問題ありませんか?

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  state = {...};
}

コンストラクターを使用して初期状態を次のように定義する場合との違いは何ですか。

class Foo extends Component {
  static defaultProps = {};

  static propTypes = {};

  constructor(props) {
    super(props);

    this.state = {...};
  }
}

具体的には、最初のアプローチでパフォーマンスに影響はありますか?

それはまったく同じことで、違いはありません。

@jhabdasそうですね、defaultPropsが次のように定義されている場合:

static defaultProps = {
}

それ以降、クラスメソッドからアクセスする方法:

this.defaultProps

undefined返します

@majioaそのクラスレベルのAPIについてはわかりませんが、1つのアイデアは、デフォルトの小道具を別のオブジェクトとしてキャッシュし、それを参照することです。 どう思いますか?

@majioa

class Foo extends React.Component {
  static defaultProps = { param: 1 };
  render() {
    return Foo.defaultProps.param;
  }
}

私は同じ問題に遭遇します、あなたはbabel-plugin-transform-class-propertiesをインストールする必要があり

npm install -D babel-plugin-transform-class-properties

次に、 "transform-class-properties"を.babelrcに追加します

{
  "presets": ["env", "react"],
  "plugins": ["react-hot-loader/babel", "transform-class-properties"]
}

static get defaultProps(){
戻る {
車:「メルセデス」
}

@ Arm7107要素が作成されるたびに新しいオブジェクトが作成されるため、これは非効率的です。 これは使用しないことを強くお勧めします。 プロパティを割り当てる:

MyComponent.defaultProps = {
  // ...
}

または、実験的な静的クラスプロパティ構文を使用します。

class MyComponent extends React.Component {
  static defaultProps = {
    // ...
  };

  // ...
}

(Babelプラグインが必要です)

Googleの結果に表示される誤った提案を防ぐために、この問題をロックします。

このページは役に立ちましたか?
0 / 5 - 0 評価