You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionreadonly(target,key,descriptor){//可以通过修改descriptor参数实现各种功能descriptor.writable=falsereturndescriptor}classPerson{
@readonlyspeak(){return'I am Person!'}}constperson=newPerson();person.speak=()=>{console.log('I am human')}
functionhandleClass(target,mixins){if(!mixins.length){thrownewSyntaxError(`@mixin() class ${target.name} requires at least one mixin as an argument`);}for(leti=0,l=mixins.length;i<l;i++){constdescs=getOwnPropertyDescriptors(mixins[i]);constkeys=getOwnKeys(descs);for(letj=0,k=keys.length;j<k;j++){constkey=keys[j];if(!(hasProperty(key,target.prototype))){defineProperty(target.prototype,key,descs[key]);}}}}exportdefaultfunctionmixin(...mixins){if(typeofmixins[0]==='function'){returnhandleClass(mixins[0],[]);}else{returntarget=>{returnhandleClass(target,mixins);};}}
对于很多初级的前端工程师对mixins的概念并不是很了解,也没有在React中尝试使用过Mixins,这边文章基本会按照Mixins的作用、用途、原理等多个方面介绍React中Mixins的使用。
首先解释一下什么是Mixins,在一些大型项目中经常会存在多个组件需要使用相同的功能的情况,如果在每个组件中都重复性的加入相同的代码,那么代码的维护性将会变的非常差,Mixins的出现就是为了解决这个问题。可以将通用共享的方法包装成Mixins方法,然后注入各个组件实现,我们首先给出一个Mixins简单的例子:
上述代码就实现了一个简单的
mixin
函数,其实质就是将mixins
中的方法遍历赋值给newObj.prototype
,从而实现mixin
返回的函数创建的对象都有mixins
中的方法。在我们大致明白了mixin
作用后,让我们来看看如何在React使用mixin
。React.createClass
假设我们所有的React组件的
props
中都含有一个默认的displayName
,在使用React.createClass
时,我们必须给每个组件中都加入当然我们,我们通过实现一个
mixin
函数,就可以实现这个功能,并且在createClass
方法使用mixin
非常简单:这样我们就实现了一个最简单的
mixin
函数,通过给每一个组件配置mixin
,我们就实现了不同组件之间共享相同的方法。需要注意的是:mixin中有相同的函数
mixin
,不同的mixin
中含有相同的非生命周期函数,React会抛出异常(不是后面的函数覆盖前面的函数)。mixin
,不同的mixin
中含有相同的生命周期函数,不会抛出异常,mixin
中的相同的生命周期函数(除render
方法)会按照createClass
中传入的mixins
数组顺序依次调用,全部调用结束后再调用组件内部的相同的声明周期函数。mixin中设置props或state
mixin
,不同的mixin
中的默认props
或初始state
中不存在相同的key值时,则默认props
和初始state
都会被合并。mixin
,不同的mixin
中默认props
或初始state
中存在相同的key值时,React会抛出异常。JSX
目前几乎很少有人会使用
React.createClass
的方式使用React,JSX + ES6成了标配,但是JavaScript在ES6之前是原生不支持的mixin
的,ES7引入了decorator,首先介绍一下decorator到底是什么?Decorator
ES7的Decorator语法类似于Python中的Decorator,在ES7中也仅仅只是一个语法糖,@decorator主要有两种,一种是面向于类(class)的@decorator,另一种是面向于方法(function)的@decorator。并且@decorator实质是利用了ES5中的
Object.defineProperty
。Object.defineProperty
关于
Object.defineProperty
不是很了解的同学其实非常推荐看一下《JavaScript高级程序设计》的第六章第一节,大概总结一下:在ES5中对象的属性其实分为两种: 数据属性和访问器属性数据属性
数据属性有四个特性:
configurable
: 属性是否可删除、重新定义enumerable
: 属性是否可枚举writable
: 属性值是否可修改value
: 属性值访问器属性
configurable
: 属性是否可删除、重新定义enumerable
: 属性是否可枚举get
: 读取属性调用set
: 设置属性调用Object.defineProperty(obj, prop, descriptor)
的三个参数是定义属性的对象、属性名和描述符,描述符本身也是Object,其中的属性就是数据属性或者访问器属性规定的参数,举个栗子:了解了
Object.defineProperty
,我们分别看下面向于类(class)的@decorator和面向于方法(function)的@decorator。面向方法的@decorator
class语法其实仅仅只是ES6的一个语法糖而已,class其实质是function。并且class中的内部方法会通过
Object.defineProperty
定义到function.prototype,例如:会被Babel转成:
Decorator函数接受的参数与
Object.defineProperty
类似,与对类(class)的方法使用@decorator,接受到的方法分别是类的prototype,内部方法名和描述符,@decorator会在调用Object.defineProperty
前劫持,先调用Decorator函数,将返回的descriptor定义到类的prototype上。例如:
面向类的@decorator
当我们对一个class使用@decorator时,接受到的参数target是类本身。例如:
讲完了@decorator,现在让我们回到JSX中,react-mixin和 core-decorators两个库都提供了mixin函数可用。大致让我们看一下core-decorators库中mixin的大致代码:
@mixin使用如下:
我们可以看到
mixin
函数相当于采用Currying的方式接受mixins
数组,返回而
handleClass
函数的大致作用就是采用defineProperty
将mixins数组中的函数定义在target.prototype上,这样就实现了mixin的要求。Mixin在React中的作用
讲了这么多Mixin的东西,那么Mixin在React中有什么作用呢?Mixin的作用无非就是在多个组件中共享相同的方法,实现复用,React中的Mixin也是相同的。比如你的组件中可能有共同的工具方法,为了避免在每个组件中都有相同的定义,你就可以采用Mixin。下面依旧举一个现实的例子。
React的性能优化一个非常常见的方法就是减少组件不必要的
render
,一般我们可以在生命周期shouldComponentUpdate(nextProps, nextState)
中进行判断,通过判断nextProps
和nextState
与this.pros
和this.state
是否完全相同(浅比较),如果相同则返回false,表示不重新渲染,如果不相同,则返回true,使得组件重新渲染(当然你也可以不使用mixin,而使用React.PureComponent也可以达到相同的效果)。并且现在有非常多的现成的库提供如上的功能,例如react-addons-pure-render-mixin
中提供了PureRenderMixin方法,首先我们可以在项目下运行:然后在代码中可以如下使用
当然你也可以这样写:
甚至这样写:
因为@decorator是ES7的用法,所以必须使用Babel才能使用,所以我们需要在
.babelrc
文件中设置:并安装插件:
之后我们就可以尽情体验ES7的decorator了!
The text was updated successfully, but these errors were encountered: