React躬行記(2)——JSX

  JSX既不是字符串,也不是HTML,而是一種相似XML,用於描述用戶界面的JavaScript擴展語法,以下代碼所示。在使用JSX時,爲了不自動插入分號時出現問題,推薦在其最外層用圓括號包裹,而且必須用一個元素包裹(例以下面的<div>元素)其它元素或文本,全部的元素還必須得閉合。html

(<div>
  <input type="text" text={getName()} />
  <button className="btn">搜索</button>
</div>)

  JSX爲視圖和數據架起了一座溝通的橋樑,它看起來與模板語言相似,但沒有創造新的模板語法,由於JSX最終會被編譯成普通的JavaScript對象,因此可以直接使用JavaScript語法。react

1、元素

  JSX中的元素稱爲React元素,分爲兩種類型:DOM元素和組件元素,前者對應原生的HTML元素,標籤的首字母要小寫;後者對應自定義元素,標籤的首字母要大寫,以下所示。算法

<button>提交</button>;            //DOM元素
<Btn>自定義按鈕</Btn>;             //組件元素

1)React.createElement()react-native

  不管是DOM元素仍是組件元素,最終都會經過Babel編譯器將它們轉換成React.createElement()方法的調用,例以下面的<button>元素。瀏覽器

<button className="btn">搜索</button>
//編譯成
React.createElement(button, { className: "btn" }, "搜索");

  React.createElement()能接收3個參數(以下所示),其中type是元素類型,也就是它的名稱;props是一個由元素屬性組成的對象;children是它的子元素(即內容),能夠是文本也能夠是其它元素。babel

React.createElement(type, [props], [...children])

  方法的返回值是一個元素對象,簡化過的對象以下所示。dom

{
  type: "button",
  props: {
    className: "btn",
    children: "搜索"
  }
}

  爲了不在多人協做時出現相同名稱的元素,能夠爲元素添加命名空間,例如調用UI模塊中的Btn元素,能夠像下面這麼寫。函數

const UI = {
  Btn: function(props) {
    return <button className={props.className}>{props.children}</button>;
  }
}
<UI.Btn className="btn">搜索</UI.Btn>

2)註釋性能

  JSX中的註釋須要像下面這樣,用一對花括號、斜槓和星號包裹。spa

{/* 表單中的提交按鈕 */}
<button>提交</button>

3)表達式

  在JSX的任意位置都能插入表達式,但必須用花括號包裹住纔能有效,例如像下面這樣調用getName()函數。注意,在JSX中不能插入語句。

function getName() {
  return "strick";
}
<div>{getName()}</div>

  因爲JSX自己就是一種表達式,所以它能夠做爲函數的參數、返回值或變量的值,以下所示。

if (true) {
  let fragment = <div>{getName()}</div>;
}

  在JSX中傳入的值都會自動被HTML轉義,這樣能夠防止XSS攻擊,例如輸入「<p></p>」,輸出「&lt;p&gt;&lt;/p&gt;」,以下所示。

//&lt;p&gt;&lt;/p&gt;
<div>{"<p></p>"}</div>

  若是要輸出不轉義的值,那麼能夠用React提供的dangerouslySetInnerHTML屬性,以下代碼所示。它的值是一個包含__html屬性的對象,其做用至關於調用DOM元素的innerHTML屬性。

<div dangerouslySetInnerHTML={{__html: "<p></p>"}}></div>

4)內容

  當元素的內容是字符串時,JSX會移除字符串中的空行,其內部的換行會被替換成一個空格,下面的兩個元素是等價的。

<p>freedom strick</p>
<p>
  freedom
          
  strick
</p>

  當元素的內容是false、null、undefined或true時,它們都不會被渲染到DOM結構中,所以下面的五個元素是等價的。

<p></p>
<p>{false}</p>
<p>{null}</p>
<p>{undefined}</p>
<p>{true}</p>

5)渲染

  若是要將React元素渲染到頁面的DOM結構中,能夠調用ReactDOM.render()方法,此方法接收3個參數,以下所示。

ReactDOM.render(element, container[, callback])

  element是要渲染的元素;container是頁面中的一個節點,在此處起到容器的做用,element會被渲染到container中;callback是可選的回調函數,會在組件被渲染或更新以後觸發。此方法的使用可參考下面的示例。

<div id="container">freedom</div>
<script type="text/babel">
  ReactDOM.render(
    <p>strick</p>, 
    document.getElementById("container") 
  );
</script>

  當第一次調用ReactDOM.render()方法時,容器內部的元素會被所有替換掉,也就是執行上面的代碼獲得的結果以下所示,原先的字符串「freedom」被替換成了<p>元素。

<div id="container">
  <p>strick</p>
</div>

2、屬性

  React對元素屬性進行了一次封裝,不只規範了屬性的命名,還完善了瀏覽器的兼容性。在JSX中,DOM元素的屬性對應標準的DOM屬性和特性;而組件元素的屬性都是無對應關係的自定義屬性。除了以「data-」和「aria-」爲前綴的元素屬性要用小寫命名以外,其他的都得遵循小駝峯命名法,例如maxlength變成maxLength、onclick變成onClick等。還有兩個比較特殊的屬性:class和for,因爲它們是JavaScript的關鍵字,所以須要變成className和htmlFor後才能使用。

1)默認值

  屬性的默認值是true,下面的兩個元素是等價的,頁面上的顯示如圖1所示。

<input type="text" value />
<input type="text" value={true} />

圖 1   帶默認值的文本框

  在標準的DOM中,諸如checked、disabled等布爾屬性,它們的值要麼爲空要麼爲對應的關鍵字,例如「checked」、「disabled」;而JSX中的布爾屬性,它們的值只能是true或false。

2)字符串和表達式

  當屬性的值是字符串時,其值須要用雙引號包裹;當屬性的值是表達式時,其值須要用花括號包裹,以下所示。

<input type="text" value="3" />
<input type="text" value={1 + 2} />

3)擴展屬性

  若是存在一個由元素屬性組成的屬性對象,那麼就能利用ES6新增的擴展運算符,把屬性對象展開並傳遞給元素,以下所示。

var props = { type: "text", value: "1" };
<input {...props} />
//至關於
<input type="text" value="1" />

  相比直接在元素上設置屬性,這種方式操做起來更加靈活。

3、虛擬DOM

  HTML文檔能被抽象成一棵由多種類型的節點構成的DOM樹,而每次對DOM節點執行增刪改查等操做,每每會觸發很是消耗性能的重繪和重排。爲了解決這個性能瓶頸,React引入了虛擬DOM。虛擬DOM(Virtual DOM)是構建在真實DOM之上的一層抽象,它將DOM元素映射成內存中的JavaScript對象(即經過React.createElement()獲得的React元素),造成一棵JavaScript對象樹。

  在React中,將虛擬DOM轉換成真實DOM的過程叫作調和(Reconciliation),而diff算法是保證調和高效的關鍵,由於diff算法會找出新舊虛擬DOM之間的差別部分,隨後只更新真實DOM中須要變化的節點,而不是將整棵DOM樹從新渲染一遍。通過虛擬DOM的隔離,開發人員已經不用再直接與頁面上的真實DOM打交道了,如圖2所示。

圖 2   新的開發模式

  虛擬DOM還有一大亮點,那就是將它與其餘渲染器配合可以集成到指定的終端,即將React元素映射成對應的原生控件,前文所描述的是用react-dom在Web端渲染,還可使用react-native在手機端(Android或iOS)渲染。

相關文章
相關標籤/搜索