轉譯是指獲取原始碼,然後使用舊版瀏覽器能理解的 JavaScript 重寫的過程。雖然兩個版本的語法不同,但功能完全一致。這與 JavaScript 的 polyfill 機制有本質區別:polyfill 完全在 JavaScript 層面解決新舊版本 API 兼容問題,將高版本 API 通過 polyfill 使低版本也能使用。但當引入新語法時(如 ES6 的 class 關鍵字),polyfill 無法兼容。因此,要在瀏覽器使用這些新語法,必須先對原始碼進行編譯(轉譯),這樣我們就能直接使用許多 ES6 新特性。
在瀏覽器中進行轉譯是最簡單的實現方式,但會給用戶帶來性能負面影響,因此對真實用戶環境不推薦使用,而是推薦在服務端進行編譯。不過這種方式對日常開發非常有利,無需設置複雜的編譯步驟。要在客戶端使用 JSX,需做兩件事:1) 包含客戶端 JSX 轉譯腳本 2) 使用 type="text/jsx" 標記 script 標籤。
舊版 React 使用 JSXTransformer,新版(v0.14+)改用 Babel。兩者用法和語法基本一致,但 Babel 除支持 JSX 外,還支持將最新 JavaScript 特性轉換為低版本語法。若無 JSX 構建腳本,瀏覽器直接包含 JSX 語法會報錯。添加構建腳本後,它會查找並轉換類型為 text/jsx 的 script 標籤內容,將 JSX 語法轉為正常 JavaScript,並自動插入到 document 中。生成的 script 同時包含 source map(轉換前後的映射),對除錯極有幫助。
上例使用內聯 script,也可使用外部 script,原理相同。但外部 script 必須部署在 HTTP 服務器上,因為構建腳本需用 XMLHttpRequest 下載外部腳本再轉換,而 XMLHttpRequest 受瀏覽器同源策略限制。
JSX 轉換非常輕量簡單,甚至保留錯誤發生的行號,可回溯 JSX 中錯誤根源。Babel 官方提供線上 JSX 轉換器:babeljs.io/repl,支持在線將 JSX 轉為 React JavaScript 方法調用代碼。另一實用工具:facebook.github.io/react/html-jsx.html,支持在線將 HTML 標籤轉為 JSX 語法。
構建 UI 時常需用到變量、條件、循環,JSX 允許在內部直接使用 JavaScript,只需用花括號 {} 包裹代碼。這類似模板引擎處理方式,若學過模板概念會很容易理解,JSX 比那些冗長的模板引擎簡單得多。當在 JSX 中使用相連的 {} 塊時,JSX 處理時會將它們分別放在標籤中區分。例如 {1}{2} 最終渲染為 12。
JSX 中的空白與 HTML 類似但不完全相同。例子 1:多個空格最終合併為一個,渲染結果為 "1 plus 2 is 3"。例子 2:標籤間無空格時渲染為 "1plus2is3"。解決方式是在 JSX 中通過插入 JavaScript 表達式添加空格,如 {' '} 或 {" "}。
這三部分參考官方文檔閱讀筆記,核心要點:JSX 註釋需用 {/* comment */} 格式;HTML 實體可直接使用或通過 Unicode 編碼;JSX 默認對輸出進行轉義,有效防範 XSS 攻擊。
參考官方文檔,提到一種有趣用法:父組件向子組件傳遞屬性。可直接用父組件的 props 傳給子組件屬性,如 <Child {...this.props} />,也可提取特定屬性傳遞。
組件的 render() 函數只能返回單一節點,對多節點需包裹在一個父組件中返回。雖然不能直接返回節點數組,但在組合過程中可使用數組,只要數組中節點有正確的 key 屬性。例外情況:數組中插入空白字符串不需設置 key。另一類似用法:從父組件接收任意數量子組件,在 render() 中渲染,如 {this.props.children}。
Facebook 官方文檔有提及但不夠全面,本書講解非常詳細。
不能使用 class 和 for 作為屬性名,它們是 ECMAScript 保留關鍵字,需用 className 和 htmlFor 替代。
style 屬性值必須是對象,而非分號分隔的字符串。所有 CSS 屬性名需用駝峰命名法,不能用連字符分隔。
HTML 中部分標籤可不閉合,但 JSX 強制要求閉合,如 <meta />。
JSX 中所有屬性名必須用駝峰命名法,如 onClick、tabIndex。