用Decorator優(yōu)化React

什么是decorator

decorator是ES6的一個(gè)新特性,可以修改class的屬性

@test
class Person {
  //do something
}
function test(tartget){
  traget.prototype.name = 'xiaoming';
  traget.prototype.sayName = function (){console.log(this.name)}
}
var p = new Person();
p.sayName();  //'xiaoming'

通過decorator,這樣就可以做到一個(gè)類的優(yōu)雅嵌套

多個(gè)decorator

@test1
@test2
@test3
@test4
class Person {
  //do something
}

實(shí)際上多個(gè)decorator會(huì)從上到下依次進(jìn)入函數(shù),然后再從下往上依次執(zhí)行。想象一下高階組件的嵌套可能會(huì)比較好理解一些

優(yōu)化React代碼

實(shí)際上根據(jù)它的用法,我們可以聯(lián)想到React高階組件

//往往我們習(xí)慣于這樣去寫高階組件,但是一旦高階組件多,則會(huì)引起書寫的不美觀
class MyComponent extends React.Component{
}
export default withRoute(connect(MyComponent))

//實(shí)際上我們可以這么寫
@withRoute
@connect
export default class MyComponent extends React.Component{
}

而且修飾器不僅用于class,我們還可以用于類里面的方法

@withRoute
export default class MyComponent extends React.Component{
  constructor() {
    //將組件的this綁定給函數(shù)
    this.handleClick = this.handleClick.bind(this)
  }

  @log
  handleClick() {
  }
}

function log(target, name, descriptor) {
  const oldValue = descriptor.value;
  const obj = { ...descriptor };
  obj.value = function (...arg) {
    const result = oldValue.apply(this, arg);
    console.log(`name: ${name} arg: ${arg} target:${JSON.stringify(target)} oldValue:${oldValue} value:${JSON.stringify(result)}`);
    return result;
  };
  return obj;
}

這里我們用組件示例,該方法可以使得每次觸發(fā)handleClick時(shí)都可以打印出信息。但是如果細(xì)心的朋友就會(huì)注意到,我們的handleClick并不是用箭頭函數(shù)寫的。這里也是值得注意的一點(diǎn),修飾器不能直接修飾箭頭函數(shù)或者匿名函數(shù),盡管這是類的方法。原因是因?yàn)楹瘮?shù)會(huì)存在提升,實(shí)際代碼如下

export default class MyComponent extends React.Component{
  @log
  handleClick = () => {
  }
}
export default class MyComponent extends React.Component{
  @log
  handleClick = function () {
  }
}
//以上兩種方法都不可以使用修飾器
export default class MyComponent extends React.Component{
  @log
  this.handleClick;
  handleClick = () => {
  }
}

Decorator用在react上的奇淫技巧

實(shí)際上我們可以自定義所有組件

// MyReact.js
import React from 'react';

export default function myComponet(target) {
  Object.setPrototypeOf(target, React.Component);
  // B 的實(shí)例繼承 A 的實(shí)例
  Object.setPrototypeOf(target.prototype, React.Component.prototype);
  return target;
}


// page.js
import myComponent from './MyReact'

@myComponent
class Page {
  render(){
    return <p>我是組件<p>
  }
}

這樣做的好處就是,我們可以在所有的組件里面添加自己的一些東西。比如埋點(diǎn)。當(dāng)然,其實(shí)不使用修飾器其實(shí)也可以做到這點(diǎn),但是這種寫法會(huì)更為簡潔。

現(xiàn)在可以使用該語法嗎

實(shí)際上這還只是個(gè)提案,babel對(duì)這個(gè)需要安裝特殊的插件才可以支持轉(zhuǎn)義該語法babel-plugin-transform-decortors-legacy。因此在使用該語法的時(shí)候,可能還需要慎重選擇。如果要調(diào)試修飾器這個(gè)語法,我只能推薦,先去Babel轉(zhuǎn)義成ES5語法,然后再在chrome上調(diào)試。轉(zhuǎn)譯時(shí)記得添加babel-plugin-transform-decortors-legacy這個(gè)插件即可

image.png

后話

關(guān)于用decorate優(yōu)化react就到這了。利用修飾器造輪子實(shí)際上也是很有藝術(shù)的一件事。

最后,我們都需要努力

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容