react入門教程二

react事件

由于react的虛擬DOM模式,react對所有的事件也都做了專門的處理和優化,官方的說法是引入了虛擬事件對象,將瀏覽器的事件進行了封裝,有著瀏覽器本地事件西安通的屬性和方法,但是沒有兼容問題。聽起來不錯,回到我們之前state的demo,handleClick(e){}加一個console.log(e)來打印一下這個點擊事件:

5

這里可以看到我們打印出來的全部是空,這是因為react給我們做了處理,把不需要的值全部隱藏了。現在我們來改一下console.log(e.target) :

6

可以看到target已經被打印出來了。如果你有時候需要的是本地的event的話可以使用e.nativeEvent來調用:

7

這里就是瀏覽器原生的event事件,但是需要注重瀏覽器兼容性。所以一般情況下最好使用react封裝好的event事件,react支持的完整事件列表可以在官方文檔查看,這里不再一一列舉。

tip:如果需要阻止默認的事件,比如form表單的默認提交,a標簽的href... 必須使用e.preventDefault() 。而需要阻止事件冒泡則需使用e.stopPropagation()。

React事件機制不同于我們以往的js事件,為提高效率,它對事件做了二次處理,將所有項目中注冊的事件全部代理(delegate)到頂層的document上,當你點擊某個DOM的時候,它會找到這個DOM和其Component,并冒泡到找到對應的事件并觸發。

比如我們經典的 ul li 結構,傳統js使用事件委托將事件綁定在ul上,而現在使用react只需要在ul上綁一個click事件,每次點擊ul里面的元素都會冒泡并觸發到ul的事件上去。但是要注意如果你在ul里面再綁定一個事件,同時不使用stopPropagation去阻止這個冒泡事件,那他會一直執行到最頂層的事件上去。

想要深入了解React事件機制?相信這篇博客會對你有所幫助——React源碼解讀系列 -- 事件機制

Refs & 真實DOM

由于react使用虛擬DOM的結構,所有的頁面變動都先在虛擬DOM上處理,只有當他們真正插入到文檔中才會轉化成真實DOM,react正是通過這樣的機制來減少DOM操作從而提高頁面的性能。

但是有時候我們確實有獲取DOM的需求,前面在學習事件的時候我們使用e.target可以獲取到真實的DOM。

而同時react也給我們提供了refs 來處理類似的情況。ref在react中是一個特殊的屬性,它可以是一個回調函數也可以是一個字符串。如果你查找國內的資料你會發現幾乎所有人用的都是ref的字符串屬性,但是在最新版(V15.4.2)的react文檔中,ref的字符串屬性被稱為’Legacy API‘ ,官方強調字符串的ref存在一些問題,并且很可能在未來的版本中將其移除。

我們先來看一下官方的demo:

var MyComponent = React.createClass({
  handleClick: function() {
    this.textInput.focus();
    console.log(this);
    console.log(this.textInput)
  },
  render: function() {
    return (
      <div>
        <input type="text" ref={(input) => { this.textInput = input; }} />
        <input type="button" value="Focus the text input" onClick={this.handleClick} />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

ref的回調函數會在組件創建或者重新渲染時立即執行,回調函數的參數即為當前組件的真實DOM,我們可以立即使用這個DOM或者將其保存以備后用。

上面代碼中輸入框的ref使用es6語法直接在組件中創建了一個回調函數,這個函數將參數input保存到this.textInput中,我這里把 this 和 this.textInput 打印出來來幫助大家更好去理解:

8

這里this指向ReactElement,即當前的的react組件,通過回調函數往this里添加了textInput對象。通過下面的this.textInput就可以看到textInput為該組件的原生DOM,我們通過ref的回調函數將該DOM存在this中,方便后面隨時調用。

簡單的ref回調我們可以直接寫在標簽中,如果復雜的話我們可以將其抽出為一個函數,在標簽中通過 ref={this.funtionName} 的形式調用。

同時我這里也有一個string refs的demo,雖然現在有很多人這樣用,但是我們要盡量避免這樣的寫法:

var MyComponent = React.createClass({
  handleClick: function() {
    this.refs.myTextInput.focus();
  },
  render: function() {
    return (
      <div>
        <input type="text" ref="myTextInput" />
        <input type="button" value="Focus the text input" onClick={this.handleClick} />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

這里給ref定義一個字符串,通過refs獲取到頁面所有的ref,再通過ref的字符串定位到該DOM,這樣操作確實方便很多,所以這個方法被廣為流傳,但是建議有使用這樣方法的童鞋最好慢慢拋棄這種寫法。

tips:有些童鞋可能網上查找資料會看到getDOMNode() or findDOMNode() 方法,在早期react中確實存在這些方法結合ref來獲取DOM,但是后來React拆分出ReactDOM后這些方法被歸到ReactDOM 的方法中,直接在react中是不能使用的。

react表單

在開始之前我們先看一個例子:

var Form = React.createClass({
  render: function() {
    return (
      <input type='text' value='這是一個輸入框'/>
    )
  }
})
ReactDOM.render(
  <Form/>,
  document.getElementById('example')
);

乍一看是不是和我們平時HTML的寫法基本一樣,但是一運行你就會發現無論如何你改變不了input中的值,鍵盤的輸入對它沒有任何影響!

react官方將帶有value的表單定義為受限組件 ,即該組件受限制于value值,他將永遠等于value的值。當然,不代表我們就不能定義表單的默認值了,官方給出了兩種解決辦法:

1,使用defaultValue。既然有受限組件,那就存在不受限組件。官方定義為不設置value的組件就是一個不受限組件,而不受限組件可以實時響應用戶的輸入將其反映到元素上。所以react就給組件定義了defaultValue來給組件設置一個非空的初始值,而對于radio,checkbox則有對應的defaultCheckd屬性來代替checkd:

 <input type='text' defaultValue='這里是默認值,也可以使用state'/>

我們可以給input定義ref的回調來獲取輸入的值:

 <input type='text' ref={(input) => { this.textInput = input; }} defaultValue='這里是默認值,也可以使用state'/>

然后通過事件獲取this.textInput.value。

比如我們一個頁面有很多輸入框,可以給他們分別定義ref,然后通過submit按鈕的提交事件來一次性全部獲取所有的輸入值。

tip:如果我們需要阻止默認的表單提交事件,需要使用e.preventDefault(),這一點我們在之前的事件里提到過。 ( ) => { } 為ES6語法,它表示為 function( ) { }

2,對于使用state來給組件設置初始值的,可以給組件綁定onChange事件,通過onChange來實時獲取用戶輸入,動態的改變state的值。這樣雖然組件受限于value,但是value的值發生了變化,那么組件的值也就跟著變化:

var Form = React.createClass({
  getInitialState:function(){
    return {
        inputValue: 'input',
    }
  },
  handleInput:function(e) {
    this.setState({inputValue: e.target.value});
  },
  render: function() {
    return (
      <input type='text' value={this.state.inputValue} onChange={this.handleInput}/>
    )
  }
})
ReactDOM.render(
  <Form/>,
  document.getElementById('example')
);

以上是使用e.target.value來獲取輸入值來刷新state,當然你也可以使用ref來獲取。

如果頁面中有很多表單,但是我們又不想使用上面的defaultValue+ref,或者我們需要在用戶輸入的時候就獲取輸入值來檢查。豈不是每一個表單組件都要定義一個onChange事件?

官方也考慮到這種問題,所以給我們提供了一個更好的解決方案:

var MyComponent = React.createClass({
  getInitialState: function() {
    return {
      isGoing: true,
      numberOfGuests: 2
    };
    this.handleInputChange = this.handleInputChange.bind(this);
  },

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  },
  
  render: function() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

通過一個onChange事件來解決所有的表單,是不是很酷!

tip: [name] 為ES6語法,它表示在對象中,name為一個變量。

tip:<textarea> 常規設置默認值采用 <textarea>這里是默認值</textarea><select> 常規設置默認值是在 <option> 中添加selected,而這對于React來說會顯得很奇怪,且不方便在后續的使用中來更新默認值。所以React中所有表單的默認值設置全部使用value(defaultValue)來定義,詳細說明參見官方文檔

生命周期

組件的生命周期分為三種:

  • Mounting:已插入真實 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真實 DOM

react為每個狀態提供兩種處理函數,will在函數狀態之前調用,did則在函數狀態之后調用:

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()

此外還有三種特殊狀態的處理函數:

  • constructor():組件調用之前的構造函數,早于componentWillMount(),常用于聲明props和state
  • componentWillReceiveProps(object nextProps):已加載組件收到新的參數時調用
  • shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時調用
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • It's a common pattern in React to wrap a component in an ...
    jplyue閱讀 3,301評論 0 2
  • 深入JSX date:20170412筆記原文其實JSX是React.createElement(componen...
    gaoer1938閱讀 8,104評論 2 35
  • 原教程內容詳見精益 React 學習指南,這只是我在學習過程中的一些閱讀筆記,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,860評論 1 18
  • 以下內容是我在學習和研究React時,對React的特性、重點和注意事項的提取、精練和總結,可以做為React特性...
    科研者閱讀 8,291評論 2 21
  • 本筆記基于React官方文檔,當前React版本號為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,798評論 14 128