『译』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...

翻译水平有限,文中带有我的理解,若有不恰当的地方,请在评论中指出,很是感谢!

相关文章
相关标签/搜索