React 中的 Mixin

React 中的 Mixin

最近在复习到 React 高阶组件相关内容的时候,发现之前比较常见的 Mixin 已经差不多被废弃了,而 HOC 相关内容也渐渐的在被 Hook 所替代,只能感叹变化太快

所以在这里打算重新的从头梳理一下,将之前博客当中关于 React 的一些过时内容也删减整合一下,也算是重新的温习一下 React 当中的几种状态逻辑复用的方式,也就是 MixinHOCHook 它们几者的实现原理、使用方法、实际应用以及如何选择等内容

我们先从快要被抛弃的 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 方法,jQueryextend 方法,这里我们来看看如何使用 _.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

×