標籤:

TypeScript在React高階組件中的使用技巧

組件參數的編譯期檢查

隨著TypeScript語言特性的完善,我們團隊的前端代碼已完全遷移至TypeScript。當前TypeScript完全支持JSX語法,舉個例子:

import * as React from reacttype Props = { p1: string}class ComponentA extends React.Component<Props> { render(){ return <div>{this.props.p1}</div> }}<ComponentA /> //編譯時錯誤,p1必須傳入<ComponentA p1="test"/> //正確

這樣我們聲明的ComponentA組件就可以在編譯時檢查傳入參數是否正確。

如果我們希望組件的某個參數是選填的,只需要在參數定義前加一個問號即可:

import * as React from reacttype Props = { p1?: string}class ComponentA extends React.Component<Props> { render(){ return <div>{this.props.p1 || "empty"}</div> }}<ComponentA /> //正確,p1為非必需參數<ComponentA p1="test"/> //正確

高階組件

在使用React的過程中,我們不可避免的會對現有組件進行再封裝,形成很多高階組件。

對於這種情況,我們首先想到的方案是編寫獨立的高階組件,如:

import * as React from reacttype BCProps = { p1: string}class BC extends React.Component<BCProps> { render(){ return <div>{this.props.p1}</div> }}type HOCProps = { p1h:string}class HOC extends React.Component<HOCProps> { render(){ return <BC p1={this.props.p1h}/> }}

在上面的例子中,BC是基礎組件,HOC是我們封裝的高階組件。我們可以看到BCProps與HOCProps是相互獨立的,這樣做的好處有以下兩點:

  1. 適用性廣,任何場景都可使用此種封裝方式。
  2. 完全解耦,使用者只需要了解HOCProps,對BCProps無需關心。

但相對的,其缺點也非常明顯,由於對BC進行了完全封裝,當BCProps改變時,如p1更改了名稱,改為了p1b,此時我們需要更改HOC的代碼,否則運行會報錯。

舉一個很常見的例子,一個基礎組件自帶樣式並不符合我們的需求,我們希望能封裝一個自定義樣式的高階組件,而其他Props保持不變。這樣的話,在樣式參數的定義不變而其他參數變動的情況下,可以做到高階組件的代碼無需進行修改。

在JS中,實現這種參數傳遞非常的簡單,但是在TS中會有些麻煩。最笨的方法是我們手動將BCProps中的樣式無關參數複製一份,但是這樣的話如果BCProps被修改,那麼我們需要手動修改HOCProps,無法做到非樣式參數改變,代碼無需修改的目的。

在當前的TS版本中,我們無法直接對已存在類型的屬性進行刪除操作,如果要實現這種高階組件,首先我們需要定義兩個幫助類型:

type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T];type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};

這樣,我們就可以實現不含樣式參數的高階組件:

import * as React from reacttype BCProps = { p1: string, style: React.CSSProperties}class BC extends React.Component<BCProps> { render(){ return <div stylex={this.props.style}>{this.props.p1}</div> }}type HOCProps = Omit<BCProps, "style">class HOC extends React.Component<HOCProps> { render(){ return <BC {...Object.assign({},this.props,{style:{color:"red"}})}/> }}

只要style參數的使用方法不變,當BC被修改時,HOC無需任何改變。

推薦閱讀:

組件庫設計實戰 - 國際化方案
Flux todoMVC 為什麼要費那麼多力氣實現一個功能!!!!,這樣寫的好處是神馬?
問一個react更新State的問題?
[上海] 招前端,移動端,小程序開發(多圖)
js fetch函數如何寫才能解決Unexpected end of JSON input?

TAG:React | TypeScript |