成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

學(xué)習(xí)es7的Decorator(順帶寫個(gè)react高階組件)

xiyang / 2190人閱讀

摘要:為了代碼進(jìn)一步解耦,可以考慮使用高階組件這種模式。開源的高階組件使用提供了一系列使用的高階組件,可以增強(qiáng)組件的行為,可以利用此庫(kù)學(xué)習(xí)高階組件的寫法。通過(guò)使用此庫(kù)提供的高階組件,可以方便地讓列表元素可拖動(dòng)。

1. Decorator基本知識(shí)

在很多框架和庫(kù)中看到它的身影,尤其是React和Redux,還有mobx中,那什么是裝飾器呢。

修飾器(Decorator)是一個(gè)函數(shù),用來(lái)修改類的行為。不是很理解這種抽象概念,還是看代碼講解實(shí)際些。

//定義一個(gè)函數(shù),也就是定義一個(gè)Decorator,target參數(shù)就是傳進(jìn)來(lái)的Class。
//這里是為類添加了一個(gè)靜態(tài)屬性
function addAge(target) {
  target.age = 2;
}

//在Decorator后面跟著Class,Decorator是函數(shù)的話,怎么不是addAge(MyGeekjcProject)這樣寫呢?
//我只能這樣理解:因?yàn)檎Z(yǔ)法就這樣,只要Decorator后面是Class,默認(rèn)就已經(jīng)把Class當(dāng)成參數(shù)隱形傳進(jìn)Decorator了(就是所謂的語(yǔ)法糖)。
@addAge
class MyGeekjcProject {}

console.log(MyGeekjcProject.age) // 2
1.1 傳參修飾類

但上面這樣只傳了一個(gè)Class作為參數(shù)不夠靈活怎么辦?
我們可以在外層套一個(gè)函數(shù),只要最后返回的是一個(gè)Decorator即可,管你套多少個(gè)函數(shù)傳多少個(gè)參數(shù)都無(wú)所謂。

function addAge(age) {
  return function(target) {
    target.age = age;
  }
}

//注意這里,隱形傳入了Class,語(yǔ)法類似于addAge(2)(MyGeekjcProject)
@testable(2)
class MyGeekjcProject {}
MyGeekjcProject.age // 2

@addAge(3)
class MyGeekjcProject {}
MyGeekjcProject.age // 3
1.2 修飾類的屬性

下面是修改類的prototype對(duì)象

function description(target) {
  target.prototype.url = "https://www.geekjc.com";
}

@description
class MyGeekjcProject {}

let geekjc = new MyGeekjcProject();
geekjc.url // https://www.geekjc.com

概念大概理解了,修飾器不僅可以修飾類,還可以修飾類的屬性

//假如修飾類的屬性則傳入三個(gè)參數(shù),對(duì)應(yīng)Object.defineProperty()里三個(gè)參數(shù),具體不細(xì)說(shuō)
//target為目標(biāo)對(duì)象,對(duì)應(yīng)為Class的實(shí)例
//name為所要修飾的屬性名,這里就是修飾器緊跟其后的name屬性
//descriptor為該屬性的描述對(duì)象
//這里的Decorator作用是使name屬性不可寫,并返回修改后的descriptor
function readonly(target, name, descriptor){
  descriptor.writable = false;
  return descriptor;
}

class Person {
  @readonly
  name() { return `${this.first} ${this.last}` }
}

關(guān)于Object.defineProperty()可以看文章學(xué)習(xí)Object.defineProperty

再看一個(gè)復(fù)雜的例子

//定義一個(gè)Class并在其add上使用了修飾器
class Math {
  @log
  add(a, b) {
    return a + b;
  }
}

//定義一個(gè)修飾器
function log(target, name, descriptor) {
  //這里是緩存舊的方法,也就是上面那個(gè)add()原始方法
  var oldValue = descriptor.value;

  //這里修改了方法,使其作用變成一個(gè)打印函數(shù)
  //最后依舊返回舊的方法,真是巧妙
  descriptor.value = function() {
    console.log(`Calling "${name}" with`, arguments);
    return oldValue.apply(null, arguments);
  };

  return descriptor;
}

const math = new Math();
math.add(2, 4);

看完上面的代碼就知道decorator有什么用了,修飾器不僅可以修飾類的行為,還可以修飾類的屬性。

2. react高階組件

更通俗地描述為,高階組件通過(guò)包裹(wrapped)被傳入的React組件,經(jīng)過(guò)一系列處理,最終返回一個(gè)相對(duì)增強(qiáng)(enhanced)的React組件,供其他組件調(diào)用。

3. 實(shí)現(xiàn)一個(gè)高階組件

面我們來(lái)實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的高階組件(函數(shù)),它接受一個(gè)React組件,包裹后然后返回。

export default function withDescription(WrappedComponent) {
  return class HOC extends Component {
    render() {
      return 
極客教程(https://www.geekjc.com)致力于推廣各種編程語(yǔ)言技術(shù),也為了未來(lái)數(shù)字化世界,讓人更容易找到操作數(shù)字化的方式,為了未來(lái)而生的編程學(xué)習(xí)平臺(tái), 大部分資源是完全免費(fèi)的,并且會(huì)根據(jù)當(dāng)前互聯(lián)網(wǎng)的變化實(shí)時(shí)更新本站內(nèi)容。
} } }

在其他組件里,我們引用這個(gè)高階組件,用來(lái)強(qiáng)化它。

@withDescription
export default class Geekjc extends Component {
  render() {
    return (
      
我是一個(gè)普通組件
); } }

在這里使用了ES7里的decorator(可以看第一節(jié)的Decorator),來(lái)提升寫法上的優(yōu)雅,但是實(shí)際上它只是一個(gè)語(yǔ)法糖,下面這種寫法也是可以的。

const?EnhanceDemo = withDescription(Geekjc);

隨后,觀察React組件樹發(fā)生了什么變化,如圖所示,可以發(fā)現(xiàn)Geekjc組件被HOC組件包裹起來(lái)了,符合了高階組件的預(yù)期,即組件是層層包裹起來(lái)的,如同洋蔥一樣。

但是隨之帶來(lái)的問(wèn)題是,如果這個(gè)高階組件被使用了多次,那么在調(diào)試的時(shí)候,將會(huì)看到一大堆HOC,所以這個(gè)時(shí)候需要做一點(diǎn)小優(yōu)化,就是在高階組件包裹后,應(yīng)當(dāng)保留其原有名稱。

我們改寫一下上述的高階組件代碼,增加了getDisplayName函數(shù)以及靜態(tài)屬性displayName,此時(shí)再去觀察DOM Tree。

function getDisplayName(component) {
  return component.displayName || component.name || "Component";
}
export default function (WrappedComponent) {
  return class HOC extends Component {
    static displayName = `HOC(${getDisplayName(WrappedComponent)})`
    render() {
      return 
極客教程(https://www.geekjc.com)致力于推廣各種編程語(yǔ)言技術(shù),也為了未來(lái)數(shù)字化世界,讓人更容易找到操作數(shù)字化的方式,為了未來(lái)而生的編程學(xué)習(xí)平臺(tái), 大部分資源是完全免費(fèi)的,并且會(huì)根據(jù)當(dāng)前互聯(lián)網(wǎng)的變化實(shí)時(shí)更新本站內(nèi)容。
} } }

此時(shí),原本組件的名稱正確地顯示在了DOM Tree上。

這個(gè)簡(jiǎn)單的例子里高階組件只做了一件事,那便是為被包裹的組件添加一個(gè)標(biāo)題樣式。這個(gè)高階組件可以用到任何一個(gè)需要添加此邏輯的組件上,只需要被此高階組件修飾即可。

由此可以看出,高階組件的主要功能是封裝并抽離組件的通用邏輯,讓此部分邏輯在組件間更好地被復(fù)用。

4. 高階組件的進(jìn)階用法 4.1 組件參數(shù)

還是以上述例子為例,此高階組件僅僅只是展示了關(guān)于網(wǎng)站的描述,但是為了更好的抽象,此描述應(yīng)當(dāng)可以被參數(shù)化,如下方式調(diào)用。

@withDescription("歡迎大家訪問(wèn)收藏(https://www.geekjc.com)") 
export default class Geekjc extends Component {
  render() {
    return (
      //...
    );
  }
}

withDescription需要被改寫成如下形式,它接受一個(gè)參數(shù),然后返回一個(gè)高階組件(函數(shù))。

export default function (description) {
  return function (WrappedComponent) {
    return class HOC extends Component {
      render() {
        return 
{description ?description : "我是描述"}
} } } }

使用ES6寫法可以更加簡(jiǎn)潔。

export default(description) => (WrappedComponent) => class HOC extends Component {
  render() {
    return 
{description ? description : "我是描述"}
} }

如圖可以看到,傳入的參數(shù)已經(jīng)反映在DOM Tree里了。

柯里化 Curry
概念:只傳遞函數(shù)的一部分參數(shù)來(lái)調(diào)用它,讓它返回一個(gè)函數(shù)去處理剩下的參數(shù)。
函數(shù)簽名:fun(params)(otherParams)
應(yīng)用:在React里,通過(guò)柯里化,我們可以通過(guò)傳入不同的參數(shù)來(lái)得到不同的高階組件。
4.2 基于屬性代理的方式

屬性代理是最常見的高階組件的使用方式,上述描述的高階組件就是這種方式。它通過(guò)做一些操作,將被包裹組件的props和新生成的props一起傳遞給此組件,這稱之為屬性代理。

export default function withHeader(WrappedComponent) {
  return class HOC extends Component {
    render() {
      const newProps = {
        test:"hoc"
      }
      // 透?jìng)鱬rops,并且傳遞新的newProps
      return 
} } }
4.3 基于反向繼承的方式

這種方式返回的React組件繼承了被傳入的組件,所以它能夠訪問(wèn)到的區(qū)域、權(quán)限更多,相比屬性代理方式,它更像打入組織內(nèi)部,對(duì)其進(jìn)行修改。具體的可以參考附錄里提供的鏈接進(jìn)行深入學(xué)習(xí)。

export default function (WrappedComponent) {
  return class Inheritance extends WrappedComponent {
    componentDidMount() {
      // 可以方便地得到state,做一些更深入的修改。
      console.log(this.state);
    }
    render() {
      return super.render();
    }
  }
}
4.4 組合多個(gè)高階組件

上述高階組件為React組件增強(qiáng)了一個(gè)功能,如果需要同時(shí)增加多個(gè)功能需要怎么做?這種場(chǎng)景非常常見,例如我既需要增加一個(gè)組件標(biāo)題,又需要在此組件未加載完成時(shí)顯示Loading。

@withDescription
@withLoading
class Demo extends Component{

}

使用compose可以簡(jiǎn)化上述過(guò)程,也能體現(xiàn)函數(shù)式編程的思想。

const enhance = compose(withHeader,withLoading);
@enhance
class Demo extends Component{

}
組合 Compose
compose可以幫助我們組合任意個(gè)(包括0個(gè))高階函數(shù),例如compose(a,b,c)返回一個(gè)新的函數(shù)d,函數(shù)d依然接受一個(gè)函數(shù)作為入?yún)ⅲ徊贿^(guò)在內(nèi)部會(huì)依次調(diào)用c,b,a,從表現(xiàn)層對(duì)使用者保持透明。
基于這個(gè)特性,我們便可以非常便捷地為某個(gè)組件增強(qiáng)或減弱其特征,只需要去變更c(diǎn)ompose函數(shù)里的參數(shù)個(gè)數(shù)便可。
compose函數(shù)實(shí)現(xiàn)方式有很多種,這里推薦其中一個(gè)recompact.compose,詳情見下方參考類庫(kù),也可以看我之前寫的一篇文章reduce與redux中compose函數(shù)
5. 與父組件區(qū)別

高階組件作為一個(gè)函數(shù),它可以更加純粹地關(guān)注業(yè)務(wù)邏輯層面的代碼,比如數(shù)據(jù)處理,數(shù)據(jù)校驗(yàn),發(fā)送請(qǐng)求等,可以改善目前代碼里業(yè)務(wù)邏輯和UI邏輯混雜在一起的現(xiàn)狀。父組件則是UI層的東西,我們先前經(jīng)常把一些業(yè)務(wù)邏輯處理放在父組件里,這樣會(huì)造成父組件混亂的情況。為了代碼進(jìn)一步解耦,可以考慮使用高階組件這種模式。

6. 開源的高階組件使用 6.1 recompact

recompact提供了一系列使用的高階組件,可以增強(qiáng)組件的行為,可以利用此庫(kù)學(xué)習(xí)高階組件的寫法。

import recompact from "recompact"
import { pure, withProps } from "recompact"

const enhance = recompact.compose(
  withProps({ className: "beautiful" }),
  pure,
)
@enhance
class Demo extends Component{

}
6.2 React Sortable

通過(guò)使用此庫(kù)提供的高階組件,可以方便地讓列表元素可拖動(dòng)。

7. 參考

recompact:包含了一系列實(shí)用的高階組件庫(kù)

React Sortable:React拖動(dòng)庫(kù)

深入理解 React 高階組件:其中詳細(xì)介紹了屬性代理和反向繼承的區(qū)別。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/98699.html

相關(guān)文章

  • react進(jìn)階漫談

    摘要:父組件向子組件之間非常常見,通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...

    neuSnail 評(píng)論0 收藏0
  • react進(jìn)階漫談

    摘要:父組件向子組件之間非常常見,通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...

    wyk1184 評(píng)論0 收藏0
  • react進(jìn)階漫談

    摘要:父組件向子組件之間非常常見,通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...

    junnplus 評(píng)論0 收藏0
  • 深入淺出React高階組件

    摘要:博客地址背景知識(shí)在開始講述高階組件前,我們先來(lái)回顧高階函數(shù)的定義接收函數(shù)作為輸入,或者輸出另一個(gè)函數(shù)的一類函數(shù),被稱作高階函數(shù)。 博客地址:http://www.luckyjing.com/post... 背景知識(shí) 在開始講述高階組件前,我們先來(lái)回顧高階函數(shù)的定義:接收函數(shù)作為輸入,或者輸出另一個(gè)函數(shù)的一類函數(shù),被稱作高階函數(shù)。對(duì)于高階組件,它描述的便是接受React組件作為輸入,輸出...

    yuanzhanghu 評(píng)論0 收藏0
  • React Mixin 前世今生

    摘要:但非常不幸,并不原生支持。這個(gè)單詞相信都很熟悉,高階函數(shù)在函數(shù)式編程是一個(gè)基本概念,它描述的是這樣一種函數(shù),接受函數(shù)作為輸入,或是輸出一個(gè)函數(shù)。比如常用的工具方法都是高階函數(shù)。恰與的定義完全一致。這種不同很可能會(huì)導(dǎo)致問(wèn)題的產(chǎn)生。 在 React component 構(gòu)建過(guò)程中,常常有這樣的場(chǎng)景,有一類功能要被不同的 Component 公用,然后看得到文檔經(jīng)常提到 Mixin(混入) ...

    姘存按 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<