React 中的 Mixin

React 中的 Mixin

最近在复习到 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() // hello

再比如下面这个 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__)
// {
// getName: ƒ ()
// setName: ƒ ()
// showName: ƒ ()
// constructor: ƒ Man()
// }

其实在很多开源库当中都提供了 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() // hello
bar.sayWorld() // world

看完了 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 章节当中来详细进行介绍

# React

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×