Help us understand the problem. What is going on with this article?

React.jsのProp

More than 3 years have passed since last update.

今回は前回にも少し登場したPropについて取り上げたいと思います。

基本的な使い方

Propは基本的にはCompnentのattributeとして定義してComponentの中ではthis.props.xxxとして参照する。それだけです。PropにはObjectでも関数でも何でも指定することが出来ます。

var Avatar = React.createClass({
  render() {
    var avatarImg = `/img/avatar_${this.props.user.id}.png`;
    return(
      <div>
        <span>{this.props.user.name}</span>
        <img src={avatarImg} />
      </div>
    );
  }
});

var user = {
  id: 10,
  name: "Hoge"
};

// <Avatar user={user} />

I/FとしてのProp

Propは外部から渡された値でそのComponentが管理している値ではないので変更してはいけません。
そのComponentが変更を管理するような値の場合は明日に紹介するStateにするべきです。

つまりPropはImmutableであり外部とのI/Fとなっています。

PropTypes

PropはComponentの外部I/FとなるものでありそうなってくるとValidationしたくなります。
そこでReact.jsではPropTypesとしてPropについての型などの制約を指定することが出来ます。

地味にいい機能ですね。

var Avatar = React.createClass({
  propTypes: {
    name:   React.PropTypes.string.isRequired,
    id:     React.PropTypes.number.isRequired,
    width:  React.PropTypes.number.isRequired,
    height: React.PropTypes.number.isRequired,
    alt:    React.PropTypes.string
  },
  render() {
    var src = `/img/avatar/${this.props.id}.png`;
    return (
      <div>
        <img src={src} width={this.props.width} height={this.props.height} alt={this.props.alt} />
        <span>{this.props.name}</span>
      </div>
    );
  }
});

<Avatar name="foo" id=1 width=100 height=100 />

こんな感じで書くことができるので、PropTypeを指定することでそのComponentのI/Fを明確に示すことが出来るようになります。

PropTypesの指定はこんな感じの指定が可能なのでかなり柔軟に指定することが出来ます。

React.PropTypes.array           // 配列
React.PropTypes.bool.isRequired // Booleanで必須
React.PropTypes.func            // 関数
React.PropTypes.number          // 数値
React.PropTypes.object          // オブジェクト
React.PropTypes.string          // 文字列
React.PropTypes.node            // Renderできるもの
React.PropTypes.element         // React Element
React.PropTypes.instanceOf(XXX) // XXXのinstanceかどうか
React.PropTypes.oneOf(['foo', 'bar']) // fooかbar
React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.array]) // 文字列か配列
React.PropTypes.arrayOf(React.PropTypes.string)  // 文字列の配列かどうか
React.PropTypes.objectOf(React.PropTypes.string) // 文字列の値を持っているか
React.PropTypes.shape({                          // 指定された形式を満たしているかどうか
  color: React.PropTypes.string,
  fontSize: React.PropTypes.number
});
React.PropTypes.any.isRequired  // なんでもいいけど必須

// カスタムの制約も定義出来る(ダメな場合はError投げる)
customPropType: function(props, propName, componentName) {
  if (!/^[0-9]/.test(props[propName])) {
    return new Error('Validation failed!');
  }
}

一番最初に紹介したコードにPropTypesを定義するとこんな感じです。

var Avatar = React.createClass({
  propTypes: {
    user: React.PropTypes.shape({
      id:   React.PropTypes.number.isRequired,
      name: React.PropTypes.string.isRequired
    })
  },
  render() {
    var avatarImg = `/img/avatar_${this.props.user.id}.png`;
    return(
      <div>
        <span>{this.props.user.name}</span>
        <img src={avatarImg} />
      </div>
    );
  }
});

注意点としては、ここで指定した制約については、パフォーマンス的な理由からProduction環境ではチェックされずに、Developでもエラーになるわけではなくてconsole.warnで出力されるのみです。

エラーにしてほしいというissueも上がってたりしたので今後エラーになるなどの変更もあるかもですが...。

デフォルト値の指定

getDefaultPropsでObjectを返すことでデフォルト値の指定も可能です。

これはComponentのインスタンスが作られる時ではなく、Componentの定義が作成されるときだけに呼ばれるのでその点注意が必要です。(明日紹介するgetInitialStateとは違う)

var Hello = React.createClass({
  getDefaultProps() {
    return {
      name: "React"
    };  
  },
  render() {
    return <div>Hello {this.props.name}</div>
  }
});

// <Hello />

setProps & replaceProps

Componentに新しいPropを渡して再度rerenderしたいような場合、setPropsとreplacePropsを使うことでPropを更新しつつrerenderすることが出来ます。

var Test = React.createClass({
  getDefaultProps: function() {
    return {
      id: 1
    };
  },
  render: function() {
    return (
      <div>{this.props.id}:{this.props.name}</div>
    );
  }
});

var component = React.render(<Test name="bar" />, document.body);

component.setProps({ name: "foo" });      // <div>1:foo</div>
component.replaceProps({ name: "hoge" }); // <div>:hoge</div>

setPropsとreplacePropsの違いは、Propの値をmergeするか置き換えるかです。
また、それぞれ第二引数にcallback関数を指定することも出来ます。


というわけで、Propの紹介でした。

明日はStateについて紹介したいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした