最近在复习到 React
高阶组件相关内容的时候,发现之前比较常见的 Mixin
已经差不多被废弃了,而 HOC
相关内容也渐渐的在被 Hook
所替代,只能感叹变化太快
所以在这里打算重新的从头梳理一下,将之前博客当中关于 React
的一些过时内容也删减整合一下,也算是重新的温习一下 React
当中的几种状态逻辑复用的方式,也就是 Mixin
,HOC
和 Hook
它们几者的实现原理、使用方法、实际应用以及如何选择等内容
我们先从快要被抛弃的 Mixin
开始看起,不过内容不会介绍很多,毕竟现在使用的已经不是很多了
Mixin 设计模式
在学习 JavaScript
的过程当中,我们可能已经听闻过 Mixin
这个东西,JavaScript
语言的设计是单一继承,即子类只能继承一个父类,不允许继承多个父类,毕竟一个对象只有一个原型,如果想实现多继承怎么办呢?所以在这种情况下就出现了 Mixin
Mixin
(混入)是一种通过扩展收集功能的方式,它本质上是将一个对象的属性拷贝到另一个对象上面去,不过你可以拷贝任意多个对象的任意个方法到一个新对象上去,这是继承所不能实现的,它的出现主要就是为了解决代码复用问题,我们可以自己尝试封装一个 Mixin
方法来感受下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function mixin (destClass, srcClass ) { var destProto = destClass.prototype var srcProto = srcClass.prototype for (var method in srcProto) { if (!destProto[method]) { destProto[method] = srcProto[method] } } } function Parent ( ) { }Parent.prototype.say = function ( ) { console .log('hello' ) } function Child ( ) { }mixin(Child, Parent) var child = new Child()child.say()
再比如下面这个 Mixin
实现多继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function mixin (destClass ) { var classes = Array .prototype.slice.call(arguments , 1 ) for (var i = 0 ; i < classes.length; i++) { var srcClass = classes[i] var srcProto = srcClass.prototype var destProto = destClass.prototype for (var method in srcProto) { if (!destProto[method]) { destProto[method] = srcProto[method] } } } } function Parent ( ) { }Parent.prototype.getName = function ( ) { } Parent.prototype.setName = function ( ) { } function Child ( ) { }Child.prototype.showName = function ( ) { } function Man ( ) { }mixin(Man, Child, Parent) var man = new Man()console .log(man.__proto__)
其实在很多开源库当中都提供了 Mixin
的实现,比如 Underscore
的 _.extend
方法,jQuery
的 extend 方法,这里我们来看看如何使用 _.extend
方法实现代码复用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var Mixin = { sayHello: function ( ) { console .log('hello' ) }, sayWorld: function ( ) { console .log('world' ) }, } function Foo ( ) { }function Bar ( ) { }_.extend(Foo.prototype, Mixin) _.extend(Bar.prototype, Mixin) var foo = new Foo()var bar = new Bar()foo.sayHello() bar.sayWorld()
看完了 Mixin
的基本使用方式以后我们再来看看如何在 React
中应用 Mixin
React 中的 Mixin React
当中也提供了 Mixin
的实现,如果完全不同的组件有相似的功能,我们可以引入来实现代码复用,但是只有在使用 createClass
来创建 React
组件时才可以使用,因为在 React
组件的 ES6
写法中它已经被废弃掉了
例如下面的例子,很多组件或页面都需要记录用户行为,性能指标等,如果我们在每个组件都引入写日志的逻辑,会产生大量重复代码,通过 Mixin
我们可以解决这一问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 var Mixin = { log: function ( ) { console .log('log' ) }, componentDidMount: function ( ) { console .log('in' ) }, componentWillUnmount: function ( ) { console .log('out' ) } } var Foo = React.createClass({ mixins: [Mixin], render: function ( ) { return <div > </div > } }) var Bar = React.createClass({ mixins: [Mixin], render: function ( ) { return <div > </div > } })
不过这种使用方式已经过时了,不再推荐使用
Mixin 带来的危害 React
官方文档在 Mixins Considered Harmful 一文中提到了 Mixin
带来了危害
Mixin
可能会相互依赖,相互耦合,不利于代码维护
不同的 Mixin
中的方法可能会相互冲突
Mixin
非常多时,组件是可以感知到的,甚至还要为其做相关处理,这样会给代码造成滚雪球式的复杂性
React
现在已经不再推荐使用 Mixin
来解决代码复用问题,因为 Mixin
带来的危害比他产生的价值还要巨大,并且 React
已经全面推荐使用高阶组件来替代它,另外高阶组件还能实现更多其他更强大的功能,所以这一部分内容我们会在后面的 React 中的 HOC 章节当中来详细进行介绍