React.jsのmixinについて

  • 59
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

今回はComponentのmixinについて書きたいと思います。

mixinはまさにmixinなので概念自体については説明しませんがComponentの共通な振る舞いをObjectとして共通化することが出来てとても便利です。

React.js自体も、LinkedStateMixinやPureRenderMixinといった形でmixinを提供しています.

ちなみにMarionette.jsでもBehaviorとして、Vue.jsでもmixinとして存在しています。

使い方

使い方はmixinsにObjectを配列として指定するだけです。
配列である通り複数指定することも出来ます。

var Logger = {
  logging(str) {
    console.log(str);
  },
  componentDidMount() {
    this.logging("component did mount");
  }
};

var Hello = React.createClass({
  mixins: [Logger],
  render() {
    this.logging("render");
    return <div>Hello</div>
  }
});

mixinが読み込まれる順番

複数mixinを指定出来るということでどのような順番で読まれるのか確認してみます。

var MixinA = {
  componentWillMount() {
    console.log("mixinA");
  }
};

var MixinB = {
  componentWillMount() {
    console.log("mixinB");
  }
};

var Hello = React.createClass({
  mixins: [MixinA, MixinB],
  componentWillMount() {
    console.log("hello");
  },
  render() {
    return <div>hello</div>
  }
});

React.render(<Hello />, document.body);
// mixinA
// mixinB
// hello

というわけで予想通り、配列の順番で呼ばれて最後にComponentのものが呼ばれるのがわかります。

Conflict State or Prop

ところで、getInitialStategetDefaultPropsなどをmixinで指定するとどうなるのでしょうか。

見てみます。

getInitialState

var Mixin = {
  getInitialState() {
    return {
      mixinValue: "mixin state"
    };
  }
};

var Hello = React.createClass({
  mixins: [Mixin],
  getInitialState() {
    return {
      componentValue: "component state"
    };
  },
  render() {
    console.log(this.state);
    return <div>hello</div>
  }
});

React.render(<Hello />, document.body);
//  Object {mixinValue: "mixin state", componentValue: "component state"}

というわけで値をmergeしてくれます。

getDefaultProps


var Mixin = {
  getDefaultProps: function() {
    return {
      mixinValue: "mixin prop"
    };
  }
};

var Hello = React.createClass({
  mixins: [Mixin],
  getDefaultProps: function() {
    return {
      componentValue: "component prop"    
    };
  },
  render: function() {
    console.log(this.props);
    return <div>hello</div>
  }
});

React.render(<Hello />, document.body);
 Object {mixinValue: "mixin prop", componentValue: "component prop"}

こちらも値をmergeしてくれます。

getInitialStateで同じkeyを指定する

var Mixin = {
  getInitialState() {
    return {
      value: "mixin state"
    };
  }
};

var Hello = React.createClass({
  mixins: [Mixin],
  getInitialState() {
    return {
      value: "component state"
    };
  },
  render() {
    console.log(this.state);
    return <div>hello</div>
  }
});

React.render(<Hello />, document.body);
//  Uncaught Error: Invariant Violation: mergeObjectsWithNoDuplicateKeys(): Tried to merge two objects with the same key: `value`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.

というわけで同じkeyの値を指定するとエラーになってしまうので注意が必要です。

二重定義

同じメソッドをmixinとComponentで定義してみます。

var Mixin = {
  foo: function() {
    console.log("mixin foo");
  }
};

var Hello = React.createClass({
  mixins: [Mixin],
  foo: function() {
    console.log("component foo");
  },
  render: function() {
    return <div>hello</div>
  }
});

React.render(<Hello />, document.body);
// Uncaught Error: Invariant Violation: ReactCompositeComponentInterface: You are attempting to define `foo` on your component more than once. This conflict may be due to a mixin.

この場合はエラーになります。


mixinをうまく使うことでコードを減らすことが出来るので、わかりにくくなりすぎない程度に使っていくと便利です。

今回はmixinについて書きました。
明日は、Addonについて書きたいと思います。

この投稿は 一人React.js Advent Calendar 201414日目の記事です。