JSX既不是字符串,也不是HTML,而是一種類似XML,用于描述用戶界面的JavaScript擴展語法,如下代碼所示。在使用JSX時,為了避免自動插入分號時出現問題,推薦在其最外層用圓括號包裹,并且必須用一個元素包裹(例如下面的元素)其它元素或文本,所有的元素還必須得閉合。
~~~html
(<div>
<input type="text" text={getName()} />
<button className="btn">搜索</button>
</div>)
~~~
  JSX為視圖和數據架起了一座溝通的橋梁,它看起來與模板語言類似,但沒有創造新的模板語法,因為JSX最終會被編譯成普通的JavaScript對象,所以能夠直接使用JavaScript語法。
## 一、元素
  JSX中的元素稱為React元素,分為兩種類型:DOM元素和組件元素,前者對應原生的HTML元素,標簽的首字母要小寫;后者對應自定義元素,標簽的首字母要大寫,如下所示。
~~~html
<button>提交</button>; //DOM元素
<Btn>自定義按鈕</Btn>; //組件元素
~~~
**1)React.createElement()**
  無論是DOM元素還是組件元素,最終都會通過Babel編譯器將它們轉換成React.createElement()方法的調用,例如下面的元素。
~~~js
<button className="btn">搜索</button>
//編譯成
React.createElement(button, { className: "btn" }, "搜索");
~~~
  React.createElement()能接收3個參數(如下所示),其中type是元素類型,也就是它的名稱;props是一個由元素屬性組成的對象;children是它的子元素(即內容),可以是文本也可以是其它元素。
~~~js
React.createElement(type, [props], [...children])
~~~
  方法的返回值是一個元素對象,簡化過的對象如下所示。
~~~json
{
type: "button",
props: {
className: "btn",
children: "搜索"
}
}
~~~
  為了避免在多人協作時出現相同名稱的元素,可以為元素添加命名空間,例如調用UI模塊中的Btn元素,可以像下面這么寫。
~~~js
const UI = {
Btn: function(props) {
return <button className={props.className}>{props.children}</button>;
}
}
<UI.Btn className="btn">搜索</UI.Btn>
~~~
**2)注釋**
  JSX中的注釋需要像下面這樣,用一對花括號、斜杠和星號包裹。
~~~js
{/* 表單中的提交按鈕 */}
<button>提交</button>
~~~
**3)表達式**
  在JSX的任意位置都能插入表達式,但必須用花括號包裹住才能有效,例如像下面這樣調用getName()函數。注意,在JSX中不能插入語句。
~~~js
function getName() {
return "strick";
}
<div>{getName()}</div>
~~~
  由于JSX本身就是一種表達式,因此它可以作為函數的參數、返回值或變量的值,如下所示。
~~~js
if (true) {
let fragment = <div>{getName()}</div>;
}
~~~
  在JSX中傳入的值都會自動被HTML轉義,這樣可以防止XSS攻擊,例如輸入“\<p>\</p>”,輸出“\<p\>\</p\>”,如下所示。
~~~js
//<p></p>
<div>{"<p></p>"}</div>
~~~
  如果要輸出不轉義的值,那么可以用React提供的dangerouslySetInnerHTML屬性,如下代碼所示。它的值是一個包含\_\_html屬性的對象,其作用相當于調用DOM元素的innerHTML屬性。
~~~html
<div dangerouslySetInnerHTML={{__html: "<p></p>"}}></div>
~~~
**4)內容**
  當元素的內容是字符串時,JSX會移除字符串中的空行,其內部的換行會被替換成一個空格,下面的兩個元素是等價的。
~~~html
<p>freedom strick</p>
<p>
freedom
strick
</p>
~~~
  當元素的內容是false、null、undefined或true時,它們都不會被渲染到DOM結構中,因此下面的五個元素是等價的。
~~~html
<p></p>
<p>{false}</p>
<p>{null}</p>
<p>{undefined}</p>
<p>{true}</p>
~~~
**5)渲染**
  如果要將React元素渲染到頁面的DOM結構中,可以調用ReactDOM.render()方法,此方法接收3個參數,如下所示。
~~~js
ReactDOM.render(element, container[, callback])
~~~
  element是要渲染的元素;container是頁面中的一個節點,在此處起到容器的作用,element會被渲染到container中;callback是可選的回調函數,會在組件被渲染或更新之后觸發。此方法的使用可參考下面的示例。
~~~html
<div id="container">freedom</div>
<script type="text/babel">
ReactDOM.render(
<p>strick</p>,
document.getElementById("container")
);
</script>
~~~
  當第一次調用ReactDOM.render()方法時,容器內部的元素會被全部替換掉,也就是執行上面的代碼得到的結果如下所示,原先的字符串“freedom”被替換成了元素。
~~~html
<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所示。
~~~html
<input type="text" value />
<input type="text" value={true} />
~~~
:-: 
:-: 圖 1 帶默認值的文本框
  在標準的DOM中,諸如checked、disabled等布爾屬性,它們的值要么為空要么為對應的關鍵字,例如“checked”、“disabled”;而JSX中的布爾屬性,它們的值只能是true或false。
**2)字符串和表達式**
  當屬性的值是字符串時,其值需要用雙引號包裹;當屬性的值是表達式時,其值需要用花括號包裹,如下所示。
~~~html
<input type="text" value="3" />
<input type="text" value={1 + 2} />
~~~
**3)擴展屬性**
  如果存在一個由元素屬性組成的屬性對象,那么就能利用ES6新增的擴展運算符,把屬性對象展開并傳遞給元素,如下所示。
~~~js
var props = { type: "text", value: "1" };
<input {...props} />
//相當于
<input type="text" value="1" />
~~~
  相比直接在元素上設置屬性,這種方式操作起來更加靈活。
## 三、虛擬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)渲染。
*****
> 原文出處:
[博客園-React躬行記](https://www.cnblogs.com/strick/category/1455720.html)
[知乎專欄-React躬行記](https://zhuanlan.zhihu.com/pwreact)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020