最近在复习到 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 章节当中来详细进行介绍