可復(fù)用組件

2019-08-14 14:28 更新

設(shè)計(jì)接口的時(shí)候,把通用的設(shè)計(jì)元素(按鈕,表單框,布局組件等)拆成接口良好定義的可復(fù)用的組件。這樣,下次開發(fā)相同界面程序時(shí)就可以寫更少的代碼,也意義著更高的開發(fā)效率,更少的 Bug 和更少的程序體積。

Prop 驗(yàn)證

隨著應(yīng)用不斷變大,保證組件被正確使用變得非常有用。為此我們引入 propTypesReact.PropTypes 提供很多驗(yàn)證器 (validator) 來(lái)驗(yàn)證傳入數(shù)據(jù)的有效性。當(dāng)向 props 傳入無(wú)效數(shù)據(jù)時(shí),JavaScript 控制臺(tái)會(huì)拋出警告。注意為了性能考慮,只在開發(fā)環(huán)境驗(yàn)證 propTypes。下面用例子來(lái)說(shuō)明不同驗(yàn)證器的區(qū)別:

React.createClass({
  propTypes: {    // 可以聲明 prop 為指定的 JS 基本類型。默認(rèn)
    // 情況下,這些 prop 都是可傳可不傳的。
    optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,    // 所有可以被渲染的對(duì)象:數(shù)字,
    // 字符串,DOM 元素或包含這些類型的數(shù)組。
    optionalNode: React.PropTypes.node,    // React 元素
    optionalElement: React.PropTypes.element,    // 用 JS 的 instanceof 操作符聲明 prop 為類的實(shí)例。
    optionalMessage: React.PropTypes.instanceOf(Message),    // 用 enum 來(lái)限制 prop 只接受指定的值。
    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),    // 指定的多個(gè)對(duì)象類型中的一個(gè)
    optionalUnion: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.instanceOf(Message)
    ]),    // 指定類型組成的數(shù)組
    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),    // 指定類型的屬性構(gòu)成的對(duì)象
    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),    // 特定形狀參數(shù)的對(duì)象
    optionalObjectWithShape: React.PropTypes.shape({
      color: React.PropTypes.string,
      fontSize: React.PropTypes.number
    }),    // 以后任意類型加上 `isRequired` 來(lái)使 prop 不可空。
    requiredFunc: React.PropTypes.func.isRequired,    // 不可空的任意類型
    requiredAny: React.PropTypes.any.isRequired,    // 自定義驗(yàn)證器。如果驗(yàn)證失敗需要返回一個(gè) Error 對(duì)象。不要直接
    // 使用 `console.warn` 或拋異常,因?yàn)檫@樣 `oneOfType` 會(huì)失效。
    customProp: function(props, propName, componentName) {      if (!/matchme/.test(props[propName])) {        return new Error('Validation failed!');
      }
    }
  },  /* ... */});

默認(rèn) Prop 值

React 支持以聲明式的方式來(lái)定義 props 的默認(rèn)值。

var ComponentWithDefaultProps = React.createClass({
  getDefaultProps: function() {    return {
      value: 'default value'
    };
  }  /* ... */});

當(dāng)父級(jí)沒有傳入 props 時(shí),getDefaultProps() 可以保證 this.props.value 有默認(rèn)值,注意 getDefaultProps 的結(jié)果會(huì)被 緩存。得益于此,你可以直接使用 props,而不必寫手動(dòng)編寫一些重復(fù)或無(wú)意義的代碼。

傳遞 Props:小技巧

有一些常用的 React 組件只是對(duì) HTML 做簡(jiǎn)單擴(kuò)展。通常,你想少寫點(diǎn)代碼來(lái)把傳入組件的 props 復(fù)制到對(duì)應(yīng)的 HTML 元素上。這時(shí) JSX 的 spread語(yǔ)法會(huì)幫到你:

var CheckLink = React.createClass({
  render: function() {    // 這樣會(huì)把 CheckList 所有的 props 復(fù)制到 <a>
    return <a {...this.props}>{'√ '}{this.props.children}</a>;
  }
});

React.render(
  <CheckLink href="/checked.html">
    Click here!
  </CheckLink>,
  document.getElementById('example')
);

單個(gè)子級(jí)

React.PropTypes.element 可以限定只能有一個(gè)子級(jí)傳入。

var MyComponent = React.createClass({
  propTypes: {
    children: React.PropTypes.element.isRequired
  },

  render: function() {    return (
      <div>
        {this.props.children} // 有且僅有一個(gè)元素,否則會(huì)拋異常。
      </div>
    );
  }

});

Mixins

組件是 React 里復(fù)用代碼最佳方式,但是有時(shí)一些復(fù)雜的組件間也需要共用一些功能。有時(shí)會(huì)被稱為 跨切面關(guān)注點(diǎn)。React 使用 mixins 來(lái)解決這類問題。

一個(gè)通用的場(chǎng)景是:一個(gè)組件需要定期更新。用 setInterval() 做很容易,但當(dāng)不需要它的時(shí)候取消定時(shí)器來(lái)節(jié)省內(nèi)存是非常重要的。React 提供 生命周期方法 來(lái)告知組件創(chuàng)建或銷毀的時(shí)間。下面來(lái)做一個(gè)簡(jiǎn)單的 mixin,使用 setInterval() 并保證在組件銷毀時(shí)清理定時(shí)器。

var SetIntervalMixin = {
  componentWillMount: function() {    this.intervals = [];
  },
  setInterval: function() {    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {    this.intervals.map(clearInterval);
  }
};var TickTock = React.createClass({
  mixins: [SetIntervalMixin], // 引用 mixin
  getInitialState: function() {    return {seconds: 0};
  },
  componentDidMount: function() {    this.setInterval(this.tick, 1000); // 調(diào)用 mixin 的方法
  },
  tick: function() {    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {    return (      <p>
        React has been running for {this.state.seconds} seconds.      </p>
    );
  }
});

React.render(  <TickTock />,
  document.getElementById('example')
);

關(guān)于 mixin 值得一提的優(yōu)點(diǎn)是,如果一個(gè)組件使用了多個(gè) mixin,并用有多個(gè) mixin 定義了同樣的生命周期方法(如:多個(gè) mixin 都需要在組件銷毀時(shí)做資源清理操作),所有這些生命周期方法都保證會(huì)被執(zhí)行到。方法執(zhí)行順序是:首先按 mixin 引入順序執(zhí)行 mixin 里方法,最后執(zhí)行組件內(nèi)定義的方法。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)