書籍完整目錄
1.2 JSX 語法
官方文檔 https://facebook.github.io/react/docs/jsx-in-depth.html
JSX 語法聽上去很討厭,但當真正使用的時候會發現,JSX 的寫法在組件的組合和屬性的傳遞上提供了非常靈活的解決方案。
在學習本節的時候,希望讀者在閲讀的同時能夠實際編碼體驗 JSX ,寫代碼的意思是真的要寫.代.碼。
1.2.1 準備 React 運行環境
為了快速開始 JSX 的學習,我們可以通過如下幾種方式快速進入 React 開發環境
方式一:Babel REPL
Babel REPL
直接在 REPL 中寫 JSX 語法,可以實時的查看編譯後的結果。
方式二:JSFiddle
在線模式 React Fiddle
方式三:本地開發
第一步:打開編輯器,新建一個 hello-react.html 文件
第二步:粘貼 Hello, world 代碼
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="http://facebook.github.io/react/js/react.js"></script>
<script src="http://facebook.github.io/react/js/react-dom.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">
var Hello = React.createClass({
render: function render() {
return <div>Hello {this.props.name}</div>;
}
});
ReactDOM.render(
<Hello name="World" />,
document.getElementById('example')
);
</script>
</body>
</html>
方式四:clone Github hello-world 分支代碼
https://github.com/leanklass/leanreact/tree/hello-world
1.2.2 JSX 語法
JSX 本質
創建 JSX 語法的本質目的是為了使用基於 xml 的方式表達組件的嵌套,保持和 HTML 一致的結構,語法上除了在描述組件上比較特別以外,其它和普通的 Javascript 沒有區別。 並且最終所有的 JSX 都會編譯為原生 Javascript。
需要提醒讀者的是,React 的很多例子都是通過 ES6 來寫的, 但這並不是 JSX 語法,後面我們會有單獨的一小節講解 ES6 的基本語法,不過目前為止我們先將跟多精力放在 JSX 上。
xml 基本規則
JSX 構建組件的規則和 xml 規則一致
嵌套規則
標籤可以任意的嵌套
eg:
function render() {
return <p>
text content
<ul>
<li>....</li>
<li>....</li>
</ul>
</p>
}
標籤閉合
標籤必須嚴格閉合,否則無法編譯通過
自閉合:
function render() {
return <input type="text"/>
}
標籤閉合:
function render() {
return <p>....</p>
}
JSX 組件
JSX 組件分為 HTML 組件和 React 組件
HTML 組件就是 HTML 中的原生標籤, 如:
function render() {
return <p> hello, React World </p>
}
function render() {
return <ul>
<li>list item 1</li>
<li>list item 2</li>
</ul>
}
React 組件就是自定義的組件,如
// 定義一個自定義組件
var CustomComponnet = React.createClass({
render: function() {
return <div> custom component </div>
}
});
// 使用自定義組件
function render() {
return <p> <CustomComponent/> </p>
}
組件屬性
和 html 一樣,JSX 中組件也有屬性,傳遞屬性的方式也相同
對於 HTML 組件
function render() {
return <p title="title" >hello, React, world </p>
}
如果是 React 組件可以定義自定義屬性,傳遞自定義屬性的方式:
function render() {
return <p> <CustomComponent customProps="data"/> </p>
}
}
屬性即可以是字符串,也可以是任意的 Javascript 變量
, 傳遞方式是將變量用花括號, eg:
function render() {
var data = {a: 1, b:2};
return <p> <CustomComponent customProps={data}/> </p>
}
需要注意的地方上,屬性的寫法上和 HTML 存在區別,在寫 JSX 的時候,所有的屬性都是駝峯式的寫法,如:
function render() {
return <div className="...">
<label htmlFor="..."></label>
<input onChange="..."/>
</div>
}
而原生的寫法為:
<div class="...">
<label for="..."></label>
<input onchange="..."/>
</div>
主要是出於標準的原因,駝峯式是 Javascript 的標準寫法,並且 React 底層是將屬性直接對應到原生 DOM 的屬性,而原生 DOM 的屬性是駝峯式的寫法,這裏也可以理解為什麼類名不是 class 而是 className 了, 又因為 class 和 for 還是 js 關鍵字,所以 jsx 中:
-
class => className
-
for => htmlFor
除此之外比較特殊的地方是 data-* 和 aria-* 兩類屬性是和 HTML 一致的。
JSX 花括號
顯示文本
很多情況,我們需要將 JS 中的文本直接顯示,做法和顯示變量屬性一樣,用花括號
function render() {
var text = "Hello, World"
return <p> {text} </p>
}
運算
花括號裏邊實際上除了變量以外,可以是一段 JS 表達式,我們可以利用花括號做簡單的運算:
funtion render() {
var text = text;
var isTrue = false;
var arr = [1, 2, 3];
return <p>
{text}
{isTrue ? "true" : "false"}
{arr.map(function(it) {
return <span> {it} </span>
})}
</p>
}
JSX 註釋
註釋的寫法如下:
function render() {
return <p>
/* 這裏是註釋內容 */
</p>
}
限制規則
render 方法返回的組件必須是有且只有一個根組件,錯誤情況的例子
// 無法編譯通過,JSX 會提示編譯錯誤
function render() {
return (<p> .... </p>
<p> .... </p>)
}
組件命名空間
JSX 可以通過命名空間的方式使用組件, 通過命名空間的方式可以解決相同名稱不同用途組件衝突的問題。
如:
function render() {
return <p>
<CustomComponent1.SubElement/>
<CustomComponent2.SubElement/>
</p>
}
1.2.3 理解 JSX
JSX 的編譯方式
JSX 的寫法最終會被編譯成原生的 Javascript。 如果你願意的話,也可以直接寫編譯後的 JS, 不過最好是寫 JSX, 因為 JSX 的目的就是為了簡化寫法,並保持和 HTML 相同的開發體驗。
JSX 具體的編譯方式有兩種
-
在 HTML 中引入 babel 編譯器, 如上 Hello World 程序中一樣。
-
離線編譯 JSX,通過 babel 編譯 JSX,細節我們將在第二章中講解。
JSX 到 JS 的轉化
Hello World 程序轉化為 JS 的代碼如下:
var Hello = React.createClass({
displayName: 'Hello',
render: function() {
return React.createElement("div", null, "Hello ", this.props.name);
}
});
ReactDOM.render(
React.createElement(Hello, {name: "World"}),
document.getElementById('container')
);
可以看出:
<Hello .../> <=> React.createElement(Hello, ....)
xml 的寫法實際上是調用 React 的工廠方法 createElement。
當理解了 JSX 最終會編譯為 JS 就可以理解 JSX 的一些特性如命名空間,組件實際上就是一個 Javascript 對象,命名空間下的組件相當於對象的屬性
1.2.4 實例練習:通過數據渲染 TODOMVC 代辦事項列表
TODOMVC 以代辦事項列表為需求模型,包含了各種框架的實現。 本例子的目的為了讓讀者能夠切身的體會 JSX 的使用方法。
問題需求
根據一個 JSON 對象,用 React JSX 的方式渲染出 TODOMVC 頁面:
JSON 對象如下:
var todolist = {
name: "todos",
todos: [{
completed: false,
title: 'finish exercise'
}, {
completed: false,
title: 'lean jsx'
}, {
completed: true,
title: 'lean react'
}]
}
修改 hello world index.html 中的代碼,為了簡化問題, 我們可以直接複製 TODOMVC 中的 HTML 和 CSS 。
Tips
-
class 要寫為 className
-
input 標籤未閉合
-
數組遍歷過後要添加 key 屬性,否則會提示 error 信息(在組件章節會講解)
-
html 轉 JSX工具, Facebook 提供了 html 轉 JSX 組件的工具,可以直接複製 html 轉為 JSX 組件
參考答案
https://github.com/leanklass/leanreact/tree/jsx