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是相互獨立的,這樣做的好處有以下兩點:
- 適用性廣,任何場景都可使用此種封裝方式。
- 完全解耦,使用者只需要了解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 |