『譯』React Mixin 的使用

update: Mixin 只適用於 ES5。若是你的項目裏面用的是 ES6 ,能夠採用高階組件來實現 Mixin 的功能。javascript

我使用 React.js 構建大型項目已經有一段時間了,我遇到過不少在不一樣的組件中都要用到相同功能的狀況。所以,我花了一個小時左右的時間去了解mixin的用法,而後分享我所學習到的一些東西。html

爲何使用 Mixin ?

React迴避子類組件,可是咱們知道,處處重複地編寫一樣的代碼是很差的。因此爲了將一樣的功能添加到多個組件當中,你須要將這些通用的功能包裝成一個mixin,而後導入到你的模塊中。 能夠說,相比繼承而已,React更喜歡這種組合的方式。嗯,我也喜歡這樣。java

寫一個簡單的 Mixin

如今假設咱們在寫一個app,咱們知道在某些狀況下咱們須要在好幾個組件當中設置默認的name屬性。
如今,咱們再也不是像之前同樣在每一個組件中寫多個一樣的getDefaultProps方法,咱們能夠像下面同樣定義一個mixinreact

var DefaultNameMixin = {
    getDefaultProps: function () {
        return {name: "Skippy"};
    }
};

它沒什麼特殊的,就是一個簡單的對象而已。ios

加入到 React 組件中

爲了使用mixin,咱們只須要簡單得在組件中加入mixins屬性,而後把剛纔咱們寫的mixin包裹成一個數組,將它做爲該屬性的值便可:git

var ComponentOne = React.createClass({
    mixins: [DefaultNameMixin],
    render: function() {
    return <h2>Hello {this.props.name}</h2>;
    }
});

React.renderComponent(<ComponentOne />, document.body);

JSFiddle 示例:一個簡單的 mixin 例子github

重複使用

就像你想象的那樣,咱們能夠在任何其餘組件中包含咱們的mixin數組

var ComponentTwo = React.createClass({
    mixins: [DefaultNameMixin],
    render: function () {
        return (
            <div>
                <h4>{this.props.name}</h4>
                <p>Favorite food: {this.props.food}</p>
            </div>
        );
    }
});

JSFiddle 示例:在多個組件中使用同一個 mixinapp

生命週期方法會被重複調用!

如何你的mixin當中包含生命週期方法,不要焦急,你仍然能夠在你的組件中使用這些方法,並且它們都會被調用:less

JSFiddle 示例:展現了兩個 default props 都會被設置

兩個getDefaultProps方法都將被調用,因此咱們能夠獲得默認爲Skippyname屬性和默認爲Pancakesfood屬性。任何一個生命週期方法或屬性都會被順利地重複調用,可是下面的狀況除外:

  • render:包含多個render方法是不行的。React 會跑出異常:

Uncaught Error: Invariant Violation: ReactCompositeComponentInterface: 
You are attempting to define `render` on your component more than once. 
This conflict may be due to a mixin.
  • displayName:你屢次的對它進行設置是沒有問題的,可是,最終的結果只以最後一次設置爲準。

須要指出的是,mixin是能夠包含在其餘的mixin中的:

var UselessMixin = {
    componentDidMount: function () {
      console.log("asdas");
    }
};

var LolMixin = {
   mixins: [UselessMixin]
};

var PantsOpinion = React.createClass({
   mixins: [LolMixin],
   render: function () {
       return (<p>I dislike pants</p>);
   }
});

React.renderComponent(<PantsOpinion />, document.body);

程序會在控制檯打印出asdas

包含多個 Mixins

咱們的mixins要包裹在數組當中,提醒了咱們能夠在組件中包含多個mixins

var DefaultNameMixin = {
    getDefaultProps: function () {
        return {name: "Lizie"};
    }
};

var DefaultFoodMixin = {
    getDefaultProps: function () {
        return {food: "Pancakes"};
    }
};

var ComponentTwo = React.createClass({
    mixins: [DefaultNameMixin, DefaultFoodMixin],
    render: function () {
        return (
            <div>
                <h4>{this.props.name}</h4>
                <p>Favorite food: {this.props.food}</p>
            </div>
        );
    }
});

注意事項

這裏有幾件事須要引發咱們的注意,當咱們使用mixins的時候。 幸運地是,這些看起來並非什麼大問題,下面是咱們在實踐當中發現的一些問題:

設置相同的 Prop 和 State

若是你嘗試在不一樣的地方定義相同的屬性時會出現下面的異常:

Uncaught Error: Invariant Violation: mergeObjectsWithNoDuplicateKeys(): 
Tried to merge two objects with the same key: name

設置相同的方法

在不一樣的mixin中定義相同的方法,或者mixin和組件中包含了相同的方法時,會拋出異常:

var LogOnMountMixin = {
    componentDidMount: function () {
        console.log("mixin mount method");
        this.logBlah()
    },
    // add a logBlah method here...
    logBlah: function () {
        console.log("blah");
    }
};

var MoreLogOnMountMixin = {
    componentDidMount: function () {
        console.log("another mixin mount method");
    },
    // ... and again here.
    logBlah: function () {
        console.log("something other than blah");
    }
};

異常信息同屢次定義rander方法時拋出的異常同樣:

Uncaught Error: Invariant Violation: ReactCompositeComponentInterface: 
You are attempting to define `logBlah` on your component more than once. 
This conflict may be due to a mixin.

多個生命週期方法的調用順序

若是咱們的組件和mixin中都包含了相同的生命週期方法的話會怎樣呢?

咱們的mixin方法首先會被調用,而後再是組件的中方法被調用。

那當咱們的組件中包含多個mixin,而這些mixin中又包含相同的生命週期方法時,調用順序又是如何?

它們會根據mixins中的順序從左到右的進行調用。

實例代碼:

var LogOnMountMixin = {
    componentDidMount: function () {
        console.log("mixin mount method");
    }
};

var MoreLogOnMountMixin = {
    componentDidMount: function () {
        console.log("another mixin mount method");
    }
};
var ComponentOne = React.createClass({
    mixins: [MoreLogOnMountMixin, LogOnMountMixin],
    componentDidMount: function () {
        console.log("component one mount method");
    },
    ...

var ComponentTwo = React.createClass({
    mixins: [LogOnMountMixin, MoreLogOnMountMixin],
    componentDidMount: function () {
        console.log("component two mount method");
    },
    ...

控制檯將輸出:

another mixin mount method
mixin mount method 
component one mount method

mixin mount method
another mixin mount method 
component two mount method

總結

Mixin 使你React程序變得更爲可重用,It's a Good Thing.
我但願這篇文章可以對你有所幫助,若是有任何反饋,很高興你可以在twitter上@veddermatic

原文連接:http://simblestudios.com/blog...

翻譯水平有限,文中帶有我的理解,若有不恰當的地方,請在評論中指出,很是感謝!

相關文章
相關標籤/搜索