在專案中引入並使用 JSX
React提供的環境搭建工具演示
配置檔案可讀性差,因此不考慮使用這種現成方式寫專案,跳過吧
我們來觀察一下宣告的這個變數:
const element = <h1>Hello, world!</h1>;複製程式碼
這種看起來可能有些奇怪的標籤語法既不是字串也不是 HTML
它被稱為 JSX, 一種 JavaScript 的語法擴充套件
推薦在 React 中使用 JSX 來描述使用者介面
JSX 乍看起來可能比較像是模版語言,但事實上它完全是在 JavaScript 內部實現的
JSX 用來宣告 React 當中的元素。在下節會詳細介紹元素是如何被渲染出來的
先來看看 JSX 的基本使用方法
在 JSX 中使用表示式
可任意地在 JSX 當中使用 JavaScript 表示式,在 JSX 當中的表示式要包含在大括號裡
例如 2 + 2
, user.firstName
, 以及 formatName(user)
都是可以使用的
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);複製程式碼
書寫 JSX 的時候一般都會帶上換行和縮排,這樣可以增強程式碼的可讀性
同樣推薦在 JSX 程式碼的外面擴上一個小括號,這樣可以防止 分號自動插入 的 bug
JSX 本身其實也是一種表示式
在編譯後,JSX 其實會被轉化為普通的 JavaScript 物件
這意味著,你其實可以在 if 或者 for 語句裡使用 JSX,將它賦值給變數,當作引數傳入,作為返回值都可以
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}複製程式碼
JSX 屬性
使用引號來定義以字串為值的屬性
const element = <div tabIndex="0"></div>;複製程式碼
使用大括號來定義以 JavaScript 表示式為值的屬性
const element = <img src={user.avatarUrl}></img>;複製程式碼
切記你使用了大括號包裹的 JavaScript 表示式時就不要再到外面套引號了
JSX 會將引號當中的內容識別為字串而不是表示式
JSX 巢狀
若 JSX 標籤是閉合式的,需在結尾處用/>
, 就好像 XML/HTML 一樣
JSX 標籤同樣可以相互巢狀
警告:
因為 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用camelCase
小駝峰命名 來定義屬性的名稱,而不是使用 HTML 的屬性名稱
如class
變成了className
而tabindex
則對應著tabIndex
JSX 防注入攻擊
可放心在 JSX 當中使用使用者輸入
React DOM 在渲染之前預設會 過濾 所有傳入的值
它可以確保你的應用不會被注入攻擊。所有的內容在渲染之前都被轉換成了字串。這樣可以有效地防止 XSS(跨站指令碼) 攻擊
JSX 代表 Objects
Babel 轉譯器會把 JSX 轉換成一個名為 React.createElement()
的方法呼叫
下面兩種程式碼的作用是完全相同的
React.createElement()
首先會進行一些避免bug的檢查,之後會返回一個類似下面例子的物件
這樣的物件被稱為 “React 元素”。它代表所有你在螢幕上看到的東西。React 通過讀取這些物件來構建 DOM 並保持資料內容一致。
我們將在下一個章節當中介紹更多有關 React 元素 是如何渲染成 DOM 的內容。
Tip:
如果你是在使用本地編輯器編寫 JSX 程式碼的話,推薦你去裝一個支援 JSX 高亮的外掛,這樣更方便之後的開發學習。
JSX 的怪異之處
JSX 偶爾也比較奇怪。針對在使用JSX 構建元件時可能會遇到的常見問題,本節彙總了一些小技巧、提示和策略來供你應對。
- 單一根節點
React 元件只能渲染一個根節點。想要了解這個限制的原因,我們先來看看render函式的一個返回示例:
return(
<h1>Hello World</h1>
)複製程式碼
它會被轉換成一條語句:
return React.createElement("h1",null,"Hello World");
但是,下面的程式碼卻不是合法的:
return (
<h1>Hello World</h1>
<h2>Have a nice day</h2>
)複製程式碼
需要明確的是,這並非JSX 的限制,而是JavaScript 的一個特性:一條返回語句只能返回單個值,而在前面的程式碼中我們嘗試返回兩條語句(兩次React.createElement 呼叫)。解決的方法非常簡單:就像你在普通JavaScript 中會做的那樣,將所有返回值包含到一個根物件中。
return (
<div>
<h1>Hello World</h1>
<h2>Have a nice day</h2>
</div>
)複製程式碼
它完全有效,因為它會被轉換成:
return React.createElement("div",null,
React.createElement("h1",null,"Hello World"),
React.createElement("h2",null," Have a nice day"),
)複製程式碼
它返回單個值,並且是通過合法的JavaScript 完成的。
- 條件語句
如果語句不相容於JSX,看上去像是JSX 的限制所致,實際上卻是因為JSX 只是普通的JavaScript
回顧一下JSX 是如何被轉換為普通JavaScript
如下JSX
return (
<div className="salutation">Hello JSX</div>
)複製程式碼
會被轉換成這樣的JavaScript
return (
React.createElement("div",{className:"salutation"},"Hello JSX");
)複製程式碼
然而,如果嘗試在JSX 的中間編寫if 語句,例如:
<div className={if (condition) { "salutation" }}>Hello JSX</div>
它就會被轉換成一個非法的JavaScript 表示式,如圖2-1 所示:
- 有什麼解決方法?
儘管並無可能在JSX 中使用“if”語句,但仍有根據條件渲染內容的方法,包括使用三元表示式和將條件賦值給一個變數(空值和未定義的值都會被React 進行處理,JSX在轉義時什麼都不會輸出)。
使用三元表示式
如果你有一個非常簡單的表示式,可以使用三元形式:
render() {
return (
<div className={condition ? "salutation" : ""}>
Hello JSX
</div>
)
}複製程式碼
這段程式碼會被轉換成一段合法的JavaScript:
React.createElement("div",{className: condition ?"salutation" : ""},
"Hello JSX");複製程式碼
三元形式還可用來有條件地渲染整個節點:
<div>
{condition ?
<span>Hello JSX</span>
: null}
</div>複製程式碼
將條件外接
如果三元表示式還不能應付你的要求,解決方法是不要在JSX 的中間使用條件。簡單地將條件語句移動到外部(就像你在第2 章中隱藏和顯示ContactItem 細節時所採取的方法)。
下面是原先的程式碼:
1. render() {
2. return (
3. <div className={if (condition) { "salutation" }}>
4. Hello JSX
5. </div>
6. )
7. }複製程式碼
將條件移動到JSX 的外部,就像:
render() {
let className;
if(condition){
className = "salutation";
}
return (
<div className={className}>Hello JSX</div>
)
}複製程式碼
React 知道如何處理未定義的值,如果條件為假,它甚至不會在div 標籤中建立class特性。