JSX既不是字符串,也不是HTML,而是一種相似XML,用於描述用戶界面的JavaScript擴展語法,以下代碼所示。在使用JSX時,爲了不自動插入分號時出現問題,推薦在其最外層用圓括號包裹,而且必須用一個元素包裹(例以下面的<div>元素)其它元素或文本,全部的元素還必須得閉合。html
(<div> <input type="text" text={getName()} /> <button className="btn">搜索</button> </div>)
JSX爲視圖和數據架起了一座溝通的橋樑,它看起來與模板語言相似,但沒有創造新的模板語法,由於JSX最終會被編譯成普通的JavaScript對象,因此可以直接使用JavaScript語法。react
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>」,輸出「<p></p>」,以下所示。
//<p></p> <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>
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" />
相比直接在元素上設置屬性,這種方式操做起來更加靈活。
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)渲染。