前言
根據 React 官方定義,React 是一個構建使用者介面的 JavaScritp Library。以 MVC 模式來說,ReactJS 主要是負責 View 的部份。過去一段時間,我們被灌輸了許多前端分離的觀念,在前端三兄弟中(或三姊妹、三劍客):HTML 掌管內容結構、CSS 負責外觀樣式,JavaScript 主管邏輯互動,千萬不要混在一塊。然而,在 React 世界裡,所有事物都是 以 Component 為基礎,將同一個 Compoent 相關的程式和資源都放在一起,而在撰寫 React Component 時我們通常會使用 JSX 的方式來提升程式撰寫效率。事實上,JSX 並非一種全新的語言,而是一種語法糖(Syntatic Sugar),一種語法類似 XML 的 ECMAScript 語法擴充。在 JSX 中 HTML 和組建這些元素標籤的程式碼有緊密的關係。因此你可能要熟悉一下以 Component 為單位的思考方式(本文主要使用 ES6 語法)。
此外,React 和 JSX 的思維在於善用 JavaScript 的強大能力,放棄蹩腳的模版語言,這和 Angular 強化 HTML 的理念也有所不同。當然 JSX 並非強制使用,你也可以選擇不用,因為最終 JSX 的內容會轉化成 JavaScript(瀏覽器只看的懂 JavaScript)。不過等你閱讀完接下來的內容,你或許會開始發現 JSX 的好,認真考慮使用 JSX 的語法。
一、使用 JSX 的好處
1. 提供更加語意化且易懂的標籤
由於 JSX 類似 XML 的語法,讓一些非開發人員也更容易看懂,且能精確定義包含屬性的樹狀結構。一般來說我們想做一個回饋表單,使用 HTML 寫法通常會長這樣:
<form class="messageBox">
<textarea></teextarea>
<button type="submit"></button>
</from>
使用 JSX,就像 XML 語法結構一樣可以自行定義標籤且有開始和關閉,容易理解:
<MessageBox />
React 思路認為使用 Component 比起模版(Template)和顯示邏輯(Display Logic)更能實現關注點分離的概念,而搭配 JSX 可以實現聲明式 Declarative
(注重 what to),而非命令式 Imperative
(注重 how to)的程式撰寫方式:
以 Facebook 上面按讚功能來說,若是命令式 Imperative
寫法大約會是長這樣:
if(userLikes()) {
if(!hasBlueLike()) {
removeGrayLike();
addBlueLike();
}
} else {
if(hasBlueLike()) {
removeBlueLike();
addGrayLike();
}
}
若是聲明式 Declarative
則是會長這樣:
if(this.state.liked) {
return (<BlueLike />);
} else {
return (<GrayLike />);
}
看完上述說明是不是感覺 React
結合 JSX
的寫法更易讀易懂?事實上,當 Component 組成越來越複雜時,若使用 JSX 將可以讓整個結構更加直觀,可讀性較高。
2. 更加簡潔
雖然最終 JSX 會轉換成 JavaScript,但使用 JSX 可以讓程式看起來更加簡潔,以下為使用 JSX 和不使用 JSX 的範例:
<a href="https://facebook.github.io/react/">Hello!</a>
不使用 JSX 的情況(記得我們說過 JSX 是選用的):
// React.createElement(元件/HTML標籤, 元件屬性,以物件表示, 子元件)
React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!')
3. 結合原生 JavaScript 語法
JSX 並非一種全新的語言,而是一種語法糖(Syntatic Sugar),一種語法類似 XML 的 ECMAScript 語法擴充,所以並沒有改變 JavaScript 語意。透過結合 JavaScript ,可以釋放 JavaScript 語言本身能力。下面例子就是運用 map
方法和 Arrow function
,輕易把 result
值迭代出來,產生無序清單(ul)的內容,不用再使用蹩腳的模版語言:
// const 為常數
const lists = ['JavaScript', 'Java', 'Node', 'Python'];
class HelloMessage extends React.Compoent {
render() {
return (
<ul>
{lists.map((result) => {
return (<li>{result}</li>);
})}
</ul>);
}
}
二、JSX 用法摘要
1. 環境設定與使用方式
初步了解為何要使用 JSX 後,我們來聊聊 JSX 的用法。一般而言 JSX 通常有兩種使用方式:
- 使用 browserify 或 webpack 等 CommonJS bundler 並整合 babel 預處理
- 於瀏覽器端做解析
在這邊簡單起見,我們先使用第二種方式,先讓大家專注熟悉 JSX 語法使用,等到後面章節再教大家使用 bundler 的方式去做解析(可以試著把下面的原始碼貼到 JSbin 的 HTML 看結果):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<!-- 請先於 index.html 中引入 react.js, react-dom.js 和 babel-core 的 browser.min.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.1/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
// 程式碼寫在這邊!
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
一般載入 JSX 方式有:
- 內嵌
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
- 從外部引入
<script type="text/jsx" src="main.jsx"></script>
2. 標籤用法
JSX 標籤非常類似 XML ,可以直接書寫。一般 Component 命名首字大寫,HTML Tags 小寫。以下是一個建立 Component 的 class:
class HelloMessage extends React.Compoent {
render() {
return (
<div>
<p>Hello React!</p>
<MessageList />
</div>
);
}
}
3. 轉換成 JavaScript
JSX 最終會轉換成瀏覽器可以讀取的 JavaScript,以下為其規則:
React.createElement(
string/ReactClass, // 表示 HTML 元素或是 React Component
[object props], // 屬性值,用物件表示
[children] // 接下來參數皆為元素子元素
)
解析前(特別注意在 JSX 中使用 JavaScript 表達式時使用 {} 括起,如下方範例的 text
,裡面對應的是變數。若需希望放置一般文字,請加上 ''
):
var text = 'Hello React';
<h1>{text}</h1>
<h1>{'text'}</h1>
解析完後:
var text = 'Hello React';
React.createElement("h1", null, "Hello React!");
另外要特別要注意的是由於 JSX 最終會轉成 JavaScript 且每一個 JSX 節點都對應到一個 JavaScript 函數,所以在 Component 的 render
方法中只能回傳一個根節點(Root Nodes)。例如:若有多個 <div>
要 render
請在外面包一個 Component 或 <div>
、<span>
元素。
4. 註解
由於 JSX 最終會編譯成 JavaScript,註解也一樣使用 //
和 /**/
當做註解方式:
// 單行註解
/*
多行註解
*/
var content = (
<List>
{/* 若是在子元件註解要加 {} */}
<Item
/* 多行
註解
喔 */
name={window.isLoggedIn ? window.name : ''} // 單行註解
/>
</List>
);
5. 屬性
在 HTML 中,我們可以透過標籤上的屬性來改變標籤外觀樣式,在 JSX 中也可以,但要注意 class
和 for
由於為 JavaScript 保留關鍵字用法,因此在 JSX 中使用 className
和 htmlFor
替代。
class HelloMessage extends React.Compoent {
render() {
return (
<div className="message">
<p>Hello React!</p>
</div>
);
}
}
Boolean 屬性
在 JSX 中預設只有屬性名稱但沒設值為 true
,例如以下第一個 input 標籤 disabled
雖然沒設值,但結果和下面的 input 為相同:
<input type="button" disabled />;
<input type="button" disabled={true} />;
反之,若是沒有屬性,則預設預設為 false
:
<input type="button" />;
<input type="button" disabled={false} />;
6. 擴展屬性
在 ES6 中使用 ...
是迭代物件的意思,可以把所有物件對應的值迭代出來設定屬性,但要注意後面設定的屬性會蓋掉前面相同屬性:
var props = {
style: "width:20px",
className: "main",
value: "yo",
}
<HelloMessage {...props} value="yo" />
// 等於以下
React.createElement("h1", React._spread({}, props, {value: "yo"}), "Hello React!");
7. 自定義屬性
若是希望使用自定義屬性,可以使用 data-
:
<HelloMessage data-attr="xd" />
8. 顯示 HTML
通常為了避免資訊安全問題,我們會過濾掉 HTML,若需要顯示的話可以使用:
<div>{{_html: '<h1>Hello World!!</h1>'}}</div>
9. 樣式使用
在 JSX 中使用外觀樣式方法如下,第一個 {}
是 JSX 語法,第二個為 JavaScript 物件。與一般屬性值用 -
分隔不同,為駝峰式命名寫法:
<HelloMessage style={{ color: '#FFFFFF', fontSize: '30px'}} />
10. 事件處理
事件處理為前端開發的重頭戲,在 JSX 中透過 inline 事件的綁定來監聽並處理事件(注意也是駝峰式寫法):
<HelloMessage onClick={this.onBtn} />
總結
以上就是 JSX 簡明入門教學,希望透過以上介紹,讓讀者了解在 React 中為何要使用 JSX,以及 JSX 基本概念和用法。最後為大家複習一下:在 React 世界裡,所有事物都是以 Component 為基礎,通常會將同一個 Compoent 相關的程式和資源都放在一起,而在撰寫 React Component 時我們常會使用 JSX 的方式來提升程式撰寫效率。JSX 是一種語法類似 XML 的 ECMAScript 語法擴充,可以善用 JavaScript 的強大能力,放棄蹩腳的模版語言。當然 JSX 並非強制使用,你也可以選擇不用,因為最終 JSX 的內容會轉化成 JavaScript。當相信閱讀完上述的內容後,你會開始認真考慮使用 JSX 的語法。
延伸閱讀
關於作者:
@kdchang 文藝型開發者,夢想是做出人們想用的產品和辦一所心目中理想的學校。A Starter & Maker. JavaScript, Python & Arduino/Android lover.:)