iT邦幫忙

DAY 29
0

Reactjs 30 天邊做邊學系列系列 第 29

Reactjs Day 29 - 其他注意事項之二

  • 分享至 

  • xImage
  •  

空值(null)的控制輸入
通常我們會在 value 的屬性是上設定值,一旦綁定值我們稱為綁定元件。這麼做可以防止使用者隨意改變 value 除非您希望這麼做。
我們在 Form 的章節討論過,React 一旦綁定值之後您就必須透過事件去修改內部的 value 參考。
您可以遇過下面這樣的問題就是已經綁定值了,但是 input 還是可以改變,這種時候要注意,你可能不小心設定值為未定義或為空。

/** @jsx React.DOM */

React.renderComponent(<input value="hi" />, mountNode);

setTimeout(function() {
  React.renderComponent(<input value={null} />, mountNode);
}, 1000);

官方的的範例可能無法清楚說明狀況讓我們在看看下面的範例:

/**
 * @jsx React.DOM
 */
var What = React.createClass({
  _onClick: function () {
    this.setProps({v: null});
  },
  render: function () {
    return (
      <div>
      <input value={this.props.v} />
      <input type='button' value="Before Click you can't change value" onClick={this._onClick} />
      </div>
    )
  }
});

React.renderComponent(
  <What v="Andy"/>,
  document.getElementById('example')
);

componentWillReceiveProps 在掛載後不會被觸發
componentWillReceiveProps 在節點掛載後不會被觸發。請參閱生命週期確認您所需要的事件。
為什麼掛載後無法收到新的 props 這是因為 componentWillReceiveProps 通常是在 render 之前拿來處理比較新舊 props,所以在一但 render 開始執行,或初始化時並不會被觸發

在 getInitialState 使用 Props 是一種反面模式(Anti-Pattern)
反面模式簡單的說就是一種不好的做法,props 通常來自父元件,而為了初始化狀態常導致我們去複製"這個資料來源"至 state 。
這邊我們得提醒只要有可能,儘量讓值是動態計算以確保資料同步差異。讓我們看看範例以理解各種情形該怎麼做

不好的範例:

/** @jsx React.DOM */

var MessageBox = React.createClass({
  getInitialState: function() {
    return {nameWithQualifier: 'Mr. ' + this.props.name};
  },

  render: function() {
    return <div>{this.state.nameWithQualifier}</div>;
  }
});

React.renderComponent(<MessageBox name="Rogers"/>, mountNode);

上面就是說,我們不該把這樣的簡單計算又在 state 存一份。正確的做法應該如下:

/** @jsx React.DOM */

var MessageBox = React.createClass({
  render: function() {
    return <div>{'Mr. ' + this.props.name}</div>;
  }
});

React.renderComponent(<MessageBox name="Rogers"/>, mountNode);

如果邏輯更複雜則您應該把他獨立成一個 method

然而如果是像下面這樣,這就不是一個反面模式了,如果您能夠清楚分離目的,一樣的資料同步不應該是最終目標:

/** @jsx React.DOM */

var Counter = React.createClass({
  getInitialState: function() {
    // naming it initialX clearly indicates that the only purpose
    // of the passed down prop is to initialize something internally
    return {count: this.props.initialCount};
  },

  handleClick: function() {
    this.setState({count: this.state.count + 1});
  },

  render: function() {
    return <div onClick={this.handleClick}>{this.state.count}</div>;
  }
});

React.renderComponent(<Counter initialCount={7}/>, mountNode);

count 和 initialCount 最終是兩個意義不同的值。

在元件中使用 DOM 事件監聽
注意: 這裡指的是附加原本的 DOM 事件而不是 React 提供的模擬事件機制。通常我們在和 jQuery 整合的時候會有這個需求。

看看下面這段調整 window 尺寸的範例碼:

/**
 * @jsx React.DOM
 */
var Box = React.createClass({
  getInitialState: function () {
    return {
      windowWidth: window.innerWidth
    };
  },
  handleResize: function (e) {
    this.setState({windowWidth: window.innerWidth})
  },
  componentDidMount: function () {
    window.addEventListener('resize', this.handleResize);
  },
  componentWillUnmount: function () {
    window.removeEventListener('resize', this.handleResize);
  },
  render: function () {
    return (
      <div>
        Current: window width: {this.state.windowWidth}
      </div>
    )
  }
});

React.renderComponent(
  <Box />,
  document.getElementById('example')
);

componentDidMount 會在元件掛載後被執行,在掛載後才會有 DOM 元素,此時我們才能附加一般的 DOM 事件上去。
注意關於事件的 callback 是綁定在元件而不是元素,React 會自動把方法綁定到當前的元件實例物件。


上一篇
Reactjs Day 28 - 其他注意事項之一
下一篇
Reactjs Day 30 - 結局,其他注意事項之三與一點點 Flux
系列文
Reactjs 30 天邊做邊學系列30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
lulubear
iT邦新手 5 級 ‧ 2014-10-14 09:46:25

29天了! (握拳)
加油喔~

0
andyyu0920
iT邦研究生 5 級 ‧ 2014-10-15 15:39:40

結束了XD

我要留言

立即登入留言