React入門教程

2018-06-19 10:55 更新
一、簡(jiǎn)介
React 起源于 Facebook 的內(nèi)部項(xiàng)目,因?yàn)樵摴緦?duì)市場(chǎng)上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來(lái)架設(shè) Instagram 的網(wǎng)站。做出來(lái)以后,發(fā)現(xiàn)這套東西很好用,就在2013年5月開源了。由于 React 的設(shè)計(jì)思想極其獨(dú)特,屬于革命性創(chuàng)新,性能出眾,代碼邏輯卻非常簡(jiǎn)單。所以,越來(lái)越多的人開始關(guān)注和使用,認(rèn)為它可能是將來(lái) Web 開發(fā)的主流工具。
ReactJS官網(wǎng)地址:http://facebook.github.io/react/

二、基礎(chǔ)模板

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>react</title> <script src="react/react.js"></script> <script src="react/react-dom.js"></script> <script src="react/browser.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> 

  /*your code*/

</script> </body> </html>


在上面的代碼中,只有一個(gè)特殊點(diǎn),那就是最后一個(gè) <script> 標(biāo)簽的 type 屬性為 text/babel。這是因?yàn)?React 獨(dú)有的 JSX 語(yǔ)法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel",通過(guò)Babel轉(zhuǎn)換成在瀏覽器中真正執(zhí)行的內(nèi)容。

其次,在這里,我們一共用了三個(gè)庫(kù): react.js 、react-dom.js 和 browser.js ,它們必須首先加載。其中,react.js 是 React 的核心庫(kù),react-dom.js 是提供與 DOM 操作相關(guān)的功能,browser.js 的作用是將 JSX 語(yǔ)法轉(zhuǎn)為 JavaScript 語(yǔ)法,這一步很消耗時(shí)間,實(shí)際上線的時(shí)候,應(yīng)該將它放到服務(wù)器完成。

三、ReactDOM.render()
ReactDOM.render 是 React 的最基本方法,用于將模板轉(zhuǎn)為 HTML 語(yǔ)言,并插入指定的 DOM 節(jié)點(diǎn)。
如下:將一個(gè) h1 標(biāo)題,插入 example 節(jié)點(diǎn)

<script type="text/babel"> ReactDOM.render( 

  <h1>Hellow World!</h1>, 

  document.getElementById("example") 

 ); </script>



注意:render里面第二個(gè)參數(shù)必須使用JavaScript原生的getElementByID方法。

四、JSX語(yǔ)法

HTML 語(yǔ)言直接寫在 JavaScript 語(yǔ)言之中,不加任何引號(hào),這就是 JSX 的語(yǔ)法,它允許 HTML 與 JavaScript 的混寫。
我們來(lái)看一個(gè)例子:

<script type="text/babel">

   var names=['Alice','Emily','Kate'];   

   ReactDOM.render(   

     <div>   

     {   

        names.map(function(name){   

          return <div>Hello {name}</div>   

        })   

     }   

     </div>,   

     document.getElementById("example")   

   );

</script>

輸出:

上面的代碼和輸出結(jié)果, 充分體現(xiàn)了JSX 的基本語(yǔ)法規(guī)則:遇到 HTML 標(biāo)簽(以 < 開頭),就用 HTML 規(guī)則解析;遇到代碼塊(以 { 開頭),就用 JavaScript 規(guī)則解析。

到這里,我們知道JSX 允許直接在模板插入 JavaScript 變量。但是,當(dāng)JavaScript變量是一個(gè)數(shù)組時(shí),會(huì)怎樣呢?

var arr=[   

<h1>Hello World</h1>,   

<h2>React</h2>   

];

ReactDOM.render(   

  <div>{arr}</div>,   

  document.getElementById("example")   

);

輸出:

從輸出結(jié)果來(lái)看, JSX 會(huì)把數(shù)組的所有成員,添加到模板里。

可以去 JSX 語(yǔ)法 里學(xué)習(xí)更多 JSX 相關(guān)的知識(shí)

到這里,我相信你對(duì)React已經(jīng)有了初步的了解,接下來(lái),我們要學(xué)習(xí)如何用React去構(gòu)建組件。

五、組件

所謂組件,即封裝起來(lái)的具有獨(dú)立功能的UI部件。React推薦以組件的方式去重新思考UI構(gòu)成,將UI上每一個(gè)功能相對(duì)獨(dú)立的模塊定義成組件,然后將小的組件通過(guò)組合或者嵌套的方式構(gòu)成大的組件,最終完成整體UI的構(gòu)建。例如,F(xiàn)acebook的instagram.com整站都采用了React來(lái)開發(fā),整個(gè)頁(yè)面就是一個(gè)大的組件,其中包含了嵌套的大量其它組件。

一個(gè)優(yōu)秀的組件,應(yīng)該具備哪些特征呢? 在React看來(lái):
(1)可組合(Composeable):一個(gè)組件易于和其它組件一起使用,或者嵌套在另一個(gè)組件內(nèi)部。如果一個(gè)組件內(nèi)部創(chuàng)建了另一個(gè)組件,那么說(shuō)父組件擁有(own)它創(chuàng)建的子組件,通過(guò)這個(gè)特性,一個(gè)復(fù)雜的UI可以拆分成多個(gè)簡(jiǎn)單的UI組件

(2)可重用(Reusable):每個(gè)組件都是具有獨(dú)立功能的,它可以被使用在多個(gè)UI場(chǎng)景;
(3)可維護(hù)(Maintainable):每個(gè)小的組件僅僅包含自身的邏輯,更容易被理解和維護(hù);

5.1 構(gòu)建組件

在React中,React.createClass 方法就用于生成一個(gè)組件類。

var HelloMessage=React.createClass({   

  render:function(){   

    return <h1>Hello {this.props.name}</h1>   

  }   

});   

ReactDOM.render(   

  <HelloMessage name="Dennis"/>,   

  document.getElementById('example')   

);

輸出:

上面的代碼中,變量HelloMessage就是一個(gè)組件類。我們?cè)谀0逯胁迦?lt;HelloMessage />時(shí),會(huì)自動(dòng)生成HelloMessage的一個(gè)實(shí)例。
注意事項(xiàng):
(1) 所有組件類都必須有自己的render方法,用于輸出組件。
(2) 組件類的第一個(gè)字母必須大寫。
(3) 組件類只能包含一個(gè)頂層標(biāo)簽。比如(<h1></h1><p></p>,這是錯(cuò)誤的。 )

相信你也注意到了,在插入<HelloMessage />時(shí),我們給了它一個(gè)name,也就是屬性。
在創(chuàng)建組件時(shí),我們可以像原生的HTML標(biāo)簽一樣,可以加入任意屬性,不過(guò),要注意的是,添加class屬性時(shí),要寫成className;添加for屬性時(shí),要寫成htmlFor。這是因?yàn)閏lass和for是JavaScript的保留字。

組件的style屬性的設(shè)置方式也值得注意,要寫成style={{width: this.props.witdh}}

var HelloMessage=React.createClass({   

  render:function(){   

    return <h1 style={{color:this.props.color}}>Hello {this.props.name}</h1>   

  }   

});   

ReactDOM.render(   

  <HelloMessage name="Dennis" color="red"/>,   

  document.getElementById('example')   

);


5.2 this.props對(duì)象

能設(shè)置屬性,我們當(dāng)然也能獲取屬性。
在React里,組件的屬性可以在組件類的this.props對(duì)象上獲取,就如上面的代碼一樣,要獲取name屬性,就通過(guò)this.props.name讀取。

this.props 對(duì)象的屬性與組件的屬性一一對(duì)應(yīng),但是,有一個(gè)例外,就是 this.props.children 屬性。它表示組件的所有子節(jié)點(diǎn)

var NotesList=React.createClass({   

  render:function(){   

    return (   

      <ul>   

      {   

         React.Children.map(this.props.children,function(child){   

           return <li>{child}</li>;   

         })   

      }   

      </ul>   

    );   

 }   

});   

ReactDOM.render(   

  <NotesList>   

    <span>Hello</span>   

    <span>World</span>   

  </NotesList>,   

  document.body   

);

輸出:



在上面的代碼中,NotesList組件有兩個(gè)span子節(jié)點(diǎn),它們都可以通過(guò)this.props.children獲取。


注意:this.props.children 的值有三種可能:如果當(dāng)前組件沒有子節(jié)點(diǎn),它就是 undefined ;如果有一個(gè)子節(jié)點(diǎn),數(shù)據(jù)類型是 object ;如果有多個(gè)子節(jié)點(diǎn),數(shù)據(jù)類型就是 array 。所以,處理 this.props.children 的時(shí)候要小心。


不過(guò),React為我們提供了React.Children工具方法來(lái)處理this.props.children。我們可以用 React.Children.map 來(lái)遍歷子節(jié)點(diǎn),而不用擔(dān)心 this.props.children 的數(shù)據(jù)類型是 undefined 還是 object。更多的 React.Children 的方法,請(qǐng)參考官方文檔。


5.3 獲取真實(shí)的DOM節(jié)點(diǎn)


在React里,其引入了虛擬DOM(Virtual DOM)的機(jī)制。所有的DOM構(gòu)造都是通過(guò)虛擬DOM進(jìn)行,每當(dāng)數(shù)據(jù)變化時(shí),React都會(huì)重新構(gòu)建整個(gè)DOM樹,然后React將當(dāng)前整個(gè)DOM樹和上一次的DOM樹進(jìn)行對(duì)比,得到DOM結(jié)構(gòu)的區(qū)別,然后僅僅將需要變化的部分進(jìn)行實(shí)際的瀏覽器DOM更新,這種算法叫做 DOM diff ,它可以極大提高網(wǎng)頁(yè)的性能表現(xiàn)。


有時(shí),我們需要從組件內(nèi)獲取真實(shí)的DOM節(jié)點(diǎn),這時(shí)就要用到 ref 屬性。

var MyFrom=React.createClass({   

  handleClick:function(){   

    console.log(this.refs.tel.value); 

  },   

  render:function(){   

    return(   

      <div>   

        <input type="text" ref="tel"/>   

        <input type="button" value="獲取電話" onClick={this.handleClick}/>   

      </div>   

    );   

  }   

});   

ReactDOM.render(   

  <MyFrom/>,   

  document.getElementById("example6")   

);

輸出:



上面代碼中,我們需要點(diǎn)擊按鈕來(lái)獲取文本輸入框的值。這時(shí),由于虛擬 DOM 是拿不到用戶輸入的,所以我們就必須獲取真實(shí)的 DOM 節(jié)點(diǎn)。而在React里,我們是通過(guò)給DOM添加 ref 屬性,然后在組件類中,使用this.refs.[refName] ,就會(huì)返回這個(gè)真實(shí)的 DOM 節(jié)點(diǎn)。  

需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實(shí) DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個(gè)屬性,否則會(huì)報(bào)錯(cuò)。上面代碼中,通過(guò)為組件指定 Click 事件的回調(diào)函數(shù),確保了只有等到真實(shí) DOM 發(fā)生 Click 事件之后,才會(huì)讀取 this.refs.[refName] 屬性。  

React 組件支持很多事件,除了 Click 事件以外,還有 KeyDown 、Copy、Scroll 等,完整的事件清單請(qǐng)查看官方文檔。


5.4  this.state

React 把用戶界面當(dāng)作簡(jiǎn)單狀態(tài)機(jī)。把用戶界面想像成擁有不同狀態(tài)然后渲染這些狀態(tài),可以輕松讓用戶界面和數(shù)據(jù)保持一致。   

React 里,只需更新組件的 state,然后根據(jù)新的 state 重新渲染用戶界面(不要操作 DOM)。React 來(lái)決定如何最高效地更新 DOM。


var LikeButton = React.createClass({   

  getInitialState: function() {   

    return {liked: false};   

  },   

  handleClick: function(event) {   

    this.setState({liked: !this.state.liked});   

  },   

  render: function() {   

    var text = this.state.liked ? 'like' : 'haven\'t liked';   

    return (   

      <p onClick={this.handleClick}>   

      You {text} this. Click to toggle.   

      </p>   

    );   

  }   

});


上面代碼是一個(gè) LikeButton 組件,它的 getInitialState 方法用于定義初始狀態(tài),也就是一個(gè)對(duì)象,這個(gè)對(duì)象可以通過(guò) this.state 屬性讀取。當(dāng)用戶點(diǎn)擊組件,導(dǎo)致狀態(tài)變化,this.setState 方法就修改狀態(tài)值,每次修改以后,自動(dòng)調(diào)用 this.render 方法,再次渲染組件。  

由于 this.props 和 this.state 都用于描述組件的特性,可能會(huì)產(chǎn)生混淆。一個(gè)簡(jiǎn)單的區(qū)分方法是,this.props 表示那些一旦定義,就不再改變的特性,而 this.state 是會(huì)隨著用戶互動(dòng)而產(chǎn)生變化的特性。


5.5 表單


諸如 <input>、<textarea>、<option> 這樣的表單組件不同于其他組件,因?yàn)樗麄兛梢酝ㄟ^(guò)用戶交互發(fā)生變化。這些組件提供的界面使響應(yīng)用戶交互的表單數(shù)據(jù)處理更加容易。

var Input = React.createClass({   

  getInitialState: function() {   

    return {value: 'Hello!'};   

  },   

  handleChange: function(event) {   

    this.setState({value: event.target.value});   

  },   

  render: function () {   

    var value = this.state.value;   

    return (   

      <div>   

         <input type="text" value={value} onChange={this.handleChange} />   

         <p>{value}</p>   

      </div>   

    );   

  }  

});   

ReactDOM.render(<Input/>, document.body);

上面代碼中,文本輸入框的值,不能用 this.props.value 讀取,而要定義一個(gè) onChange 事件的回調(diào)函數(shù),通過(guò) event.target.value 讀取用戶輸入的值。textarea 元素、select元素、radio元素都屬于這種情況,更多介紹請(qǐng)參考官方文檔。





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

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)