裝飾器(Decorator)和React高階組件(HOC)

什麼是裝飾器(Decorator)

裝飾器(Decorator)是一種與類(class)相關的語法,用來註釋或修改類和類方法。 裝飾器是一種函數,寫成@ + 函數名。它能夠放在類和類方法的定義前面。 其實只是一個語法糖. 尚未正式發佈, 還須要插件babel-plugin-transform-decorators-legacy使用react

裝飾器(Decorator)使用

類的裝飾器

@testable
class MyTestableClass {
  // ...
}

function testable(target) {
  target.isTestable = true;
}

MyTestableClass.isTestable // true
複製代碼

上面代碼中,@testable就是一個裝飾器。它修改了MyTestableClass這個類的行爲,爲它加上了靜態屬性isTestabletestable函數的參數targetMyTestableClass類自己。es6

也就是說,裝飾器是一個對類進行處理的函數。裝飾器函數的第一個參數,就是所要裝飾的目標類。bash

function testable(target) {
  // ...
}
複製代碼

若是想傳參,能夠在裝飾器外面再封裝一層函數。babel

function testable(isTestable) {
  return function(target) {
    target.isTestable = isTestable;
  }
}

@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true

@testable(false)
class MyClass {}
MyClass.isTestable // false
複製代碼

上面代碼中,裝飾器testable能夠接受參數,這就等於能夠修改裝飾器的行爲。函數

注意,裝飾器對類的行爲的改變,是代碼編譯時發生的,而不是在運行時。這意味着,裝飾器能在編譯階段運行代碼。也就是說,裝飾器本質就是編譯時執行的函數。ui

前面的例子是爲類添加一個靜態屬性,若是想添加實例屬性,能夠經過目標類的prototype對象操做。lua

function testable(target) {
  target.prototype.isTestable = true;
}

@testable
class MyTestableClass {}

let obj = new MyTestableClass();
obj.isTestable // true
複製代碼

上面代碼中,裝飾器函數testable是在目標類的prototype對象上添加屬性,所以就能夠在實例上調用。spa

function testable(target) {
  target.prototype.isTestable = true;
}

@testable
class MyTestableClass {}

let obj = new MyTestableClass();
obj.isTestable // true
複製代碼
  • 實際開發中,React 與 Redux 庫結合使用時

經常須要寫成下面這樣prototype

class MyReactComponent extends React.Component {}

export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
複製代碼

有了裝飾器,就能夠改寫上面的代碼。插件

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
複製代碼

類的方法的裝飾器

function readonly(target, name, descriptor){
  // descriptor對象原來的值以下
  // {
  //   value: specifiedFunction,
  //   enumerable: false,
  //   configurable: true,
  //   writable: true
  // };
  descriptor.writable = false;
  return descriptor;
}

readonly(Person.prototype, 'name', descriptor);
// 相似於
Object.defineProperty(Person.prototype, 'name', descriptor);
複製代碼

裝飾器第一個參數是類的原型對象,上例是Person.prototype,裝飾器的本意是要「裝飾」類的實例,可是這個時候實例還沒生成,因此只能去裝飾原型(這不一樣於類的裝飾,那種狀況時target參數指的是類自己);第二個參數是所要裝飾的屬性名,第三個參數是該屬性的描述對象。

其他使用方法與類的裝飾器相同(參數變爲3個了~)

多個裝飾器

若是同一個方法有多個裝飾器,會像剝洋蔥同樣,先從外到內進入,而後由內向外執行。

function dec(id){
  console.log('evaluated', id);
  return (target, property, descriptor) => console.log('executed', id);
}

class Example {
    @dec(1)
    @dec(2)
    method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1
複製代碼

裝飾器不能做用於函數

裝飾器只能用於類和類的方法,不能用於函數,由於存在函數提高。

React高階組件(HOC)

import React from 'react';

export default Component => class extends React.Component {
  render() {
    return <div style={{cursor: 'pointer', display: 'inline-block'}}>
      <Component/>
    </div>
  }
}
複製代碼

這個裝飾器(高階組件)接受一個 React 組件做爲參數,而後返回一個新的 React 組件。實現很簡單,就是包裹了一層 div,添加了一個 style,就這麼簡單。之後全部被它裝飾的組件都會具備這個特徵。 除了style還能夠傳參數

import React from 'react';

export default Component => class extends React.Component {
  render() {
    return <div test={'qwe'}>
      <Component/>
    </div>
  }
}
複製代碼

之後全部被它裝飾的組件均可以從props裏面獲取到test. 他的值是'qwe'

擴展

發揮你的想象, 你能夠寫無數個很方便的高階組件, 經過裝飾器的方式, 讓你的代碼更簡潔, 更帥

索引

es6.ruanyifeng.com/#docs/decor…

相關文章
相關標籤/搜索