官术网_书友最值得收藏!

2.2.1 React的prop

在React中,prop(property的簡寫)是從外部傳遞給組件的數(shù)據(jù),一個React組件通過定義自己能夠接受的prop就定義了自己的對外公共接口。

每個React組件都是獨立存在的模塊,組件之外的一切都是外部世界,外部世界就是通過prop來和組件對話的。

1.給prop賦值

我們先從外部世界來看,prop是如何使用的,在下面的JSX代碼片段中,就使用了prop:

<SampleButton
  id="sample" borderWidth={2} onClick={onButtonClick}
  style={{color: "red"}}
/>

在上面的例子中,創(chuàng)建了名為SampleButton的組件實例,使用了名字分別為id、border Width、onClick和style的prop,看起來,React組件的prop很像是HTML元素的屬性,不過,HTML組件屬性的值都是字符串類型,即使是內(nèi)嵌JavaScript,也依然是字符串形式表示代碼。React組件的prop所能支持的類型則豐富得多,除了字符串,可以是任何一種JavaScript語言支持的數(shù)據(jù)類型。

比如在上面的SampleButton中,borderWidth就是數(shù)字類型,onClick是函數(shù)類型,style的值是一個包含color字段的對象,當prop的類型不是字符串類型時,在JSX中必須用花括號{}把prop值包住,所以style的值有兩層花括號,外層花括號代表是JSX的語法,內(nèi)層的花括號代表這是一個對象常量。

當外部世界要傳遞一些數(shù)據(jù)給React組件,一個最直接的方式就是通過prop;同樣,React組件要反饋數(shù)據(jù)給外部世界,也可以用prop,因為prop的類型不限于純數(shù)據(jù),也可以是函數(shù),函數(shù)類型的prop等于讓父組件交給了子組件一個回調(diào)函數(shù),子組件在恰當?shù)膶嶋H調(diào)用函數(shù)類型的prop,可以帶上必要的參數(shù),這樣就可以反過來把信息傳遞給外部世界。

對于Counter組件,父組件ControlPanel就是外部世界,我們看ControlPanel是如何用prop傳遞信息給Counter的,代碼如下:

class ControlPanel extends Component {
  render() {
    return (
      <div>
        <Counter caption="First" initValue={0} />
        <Counter caption="Second" initValue={10} />
        <Counter caption="Third" initValue={20} />
      </div>
    );
  }
}

ControlPanel組件包含三個Counter組件實例,在ControlPanel的render函數(shù)中將這三個子組件實例用div包起來,因為React要求render函數(shù)只能返回一個元素。

提示

雖然React聲稱將來可以支持render返回數(shù)組以支持多個組件,但是到本書寫作時最新版v15.4為止,這個功能依然沒有實現(xiàn)。

在每個Counter組件實例中,都使用了caption和initValue兩個prop。通過名為caption的prop, ControlPanel傳遞給Counter組件實例說明文字。通過名為initValue的prop傳遞給Counter組件一個初始的計數(shù)值。

2.讀取prop值

我們再來看Counter組件內(nèi)部是如何接收傳入的prop的,首先是構(gòu)造函數(shù),代碼如下:

class Counter extends Component {
  constructor(props) {
    super(props);

    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

    this.state = {
      count: props.initValue || 0
    }
  }

如果一個組件需要定義自己的構(gòu)造函數(shù),一定要記得在構(gòu)造函數(shù)的第一行通過super調(diào)用父類也就是React.Component的構(gòu)造函數(shù)。如果在構(gòu)造函數(shù)中沒有調(diào)用super(props),那么組件實例被構(gòu)造之后,類實例的所有成員函數(shù)就無法通過this.props訪問到父組件傳遞過來的props值。很明顯,給this.props賦值是React.Component構(gòu)造函數(shù)的工作之一。

在Counter的構(gòu)造函數(shù)中還給兩個成員函數(shù)綁定了當前this的執(zhí)行環(huán)境,因為ES6方法創(chuàng)造的React組件類并不自動給我們綁定this到當前實例對象。

在構(gòu)造函數(shù)的最后,我們可以看到讀取傳入prop的方法,在構(gòu)造函數(shù)中可以通過參數(shù)props獲得傳入prop值,在其他函數(shù)中則可以通過this.props訪問傳入prop的值,比如在Counter組件的render函數(shù)中,我們就是通過this.props獲得傳入的caption, render函數(shù)代碼如下:

render() {
  const {caption} = this.props;
  return (
    <div>
  <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
  <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
  <span>{caption} count: {this.state.count}</span>
  </div>
  );
}

在上面的代碼中,我們使用了ES6的解構(gòu)賦值(destructuring assignment)語法從this. props中獲得了名為caption的prop值。

3. propTypes檢查

既然prop是組件的對外接口,那么就應(yīng)該有某種方式讓組件聲明自己的接口規(guī)范。簡單說,一個組件應(yīng)該可以規(guī)范以下這些方面:

□ 這個組件支持哪些prop;

□ 每個prop應(yīng)該是什么樣的格式。

React通過propTypes來支持這些功能。

在ES6方法定義的組件類中,可以通過增加類的propTypes屬性來定義prop規(guī)格,這不只是聲明,而且是一種限制,在運行時和靜態(tài)代碼檢查時,都可以根據(jù)propTypes判斷外部世界是否正確地使用了組件的屬性。

比如,對于Counter組件的propTypes定義代碼如下:

Counter.propTypes = {
  caption: PropTypes.string.isRequired,
  initValue: PropTypes.number
};

其中要求caption必須是string類型,initValue必須是number類型??梢钥吹剑瑑烧叱祟愋筒煌猓€有一個區(qū)別:caption帶上了isRequried,這表示使用Counter組件必須要指定caption;而initValue因為沒有isRequired,則表示如果沒有也沒關(guān)系。

為了驗證propTypes的作用,可以嘗試故意違反propTypes的規(guī)定使用Counter實例,比如在ControlPanel的render函數(shù)中增加下列的代碼:

<Counter caption={123} initValue={20} />

我們在Chrome瀏覽器開發(fā)工具的Console界面,可以看到一個紅色的警告提示,如圖2-2所示。

圖2-2 錯誤prop類型的錯誤提示

這段出錯的含義是,caption屬性預(yù)期是字符串類型,得到的卻是一個數(shù)字類型。

我們嘗試刪掉這個Counter實例的caption屬性,代碼如下:

<Counter initValue={20} />

這時可以看到Console選項卡中依然有紅色警告信息,如圖2-3所示。

圖2-3 缺失必須存在prop的錯誤提示

提示的含義是,caption是Counter必需的屬性,但是卻沒有賦值。

很明顯,有了propTypes的檢查,可以很容易發(fā)現(xiàn)對prop的不正確使用方法,可盡早發(fā)現(xiàn)代碼中的錯誤。

從上面可以看得出來propTypes檢查可以防止不正確的prop使用方法,那么如果組件根本就沒有定義propTypes會怎么樣呢?

可以嘗試在src/Counter.js文件中刪除掉那一段給Counter.propTypes賦值的語句,在瀏覽器Console里可以看到紅色警告不再出現(xiàn)??梢?,沒有propTypes定義,組件依然能夠正常工作,而且,即使在上面propTypes檢查出錯的情況下,組件依舊能工作。也就是說propTypes檢查只是一個輔助開發(fā)的功能,并不會改變組件的行為。

propTypes雖然能夠在開發(fā)階段發(fā)現(xiàn)代碼中的問題,但是放在產(chǎn)品環(huán)境中就不大合適了。

首先,定義類的propTypes屬性,無疑是要占用一些代碼空間,而且propTypes檢查也是要消耗CPU計算資源的。其次,在產(chǎn)品環(huán)境下做propTypes檢查沒有什么幫助,畢竟,propTypes產(chǎn)生的這些錯誤信息只有開發(fā)者才能看得懂,放在產(chǎn)品環(huán)境下,在最終用戶的瀏覽器Console中輸出這些錯誤信息沒什么意義。

所以,最好的方式是,開發(fā)者在代碼中定義propTypes,在開發(fā)過程中避免犯錯,但是在發(fā)布產(chǎn)品代碼時,用一種自動的方式將propTypes去掉,這樣最終部署到產(chǎn)品環(huán)境的代碼就會更優(yōu)?,F(xiàn)有的babel-react-optimize就具有這個功能,可以通過npm安裝,但是應(yīng)該確保只在發(fā)布產(chǎn)品代碼時使用它。

主站蜘蛛池模板: 福泉市| 吴旗县| 扶沟县| 枝江市| 高安市| 榆社县| 蒙城县| 锦州市| 婺源县| 沁水县| 崇左市| 赤水市| 临泉县| 安泽县| 嘉峪关市| 顺义区| 淳化县| 逊克县| 隆子县| 清水县| 景宁| 青岛市| 哈巴河县| 米泉市| 吉安市| 桂林市| 小金县| 淮阳县| 满城县| 阿鲁科尔沁旗| 汾西县| 屏南县| 石嘴山市| 星子县| 临颍县| 昆山市| 台前县| 梓潼县| 泸西县| 富源县| 通城县|