深入了解React的概念之一: JSX

一、什么是JSX

使用JSX聲明一個(gè)變量(React 當(dāng)中的元素):

const element = <h1>Hello, world!</h1>;

JSX是一種 JavaScript 的語法擴(kuò)展。 我們推薦在 React 中使用 JSX 來描述用戶界面。JSX 乍看起來可能比較像是模版語言,但事實(shí)上它完全是在 JavaScript 內(nèi)部實(shí)現(xiàn)的。

二、為什么要使用JSX

傳統(tǒng)的 MVC 是將模板放在其他地方,比如 <script> 標(biāo)簽或者模板文件,再在 JS 中通過某種手段引用模板。按照這種思路,想想多少次我們面對四處分散的模板片段不知所措?糾結(jié)模板引擎,糾結(jié)模板存放位置,糾結(jié)如何引用模板……下面是一段 React 官方的看法:

We strongly believe that components are the right way to separate concerns rather than "templates" and "display logic." We think that markup and the code that generates it are intimately tied together. Additionally, display logic is often very complex and using template languages to express it becomes cumbersome.

簡單來說,React 認(rèn)為組件才是王道,而組件是和模板緊密關(guān)聯(lián)的, JSX 這種語法,就是為了把HTML模板直接嵌入到JS代碼里面,這樣就做到了模板和組件關(guān)聯(lián),但是 JS 不支持這種包含 HTML 的語法,所以需要通過工具將 JSX 編譯輸出成 JS 代碼才能使用。

npm install babel-loader --save-dev


三、載入方式

JSX 目前有兩種方法載入。

1. 內(nèi)聯(lián)方式載入
<script type="text/babel">
    ReactDOM.render(
      <h1>hello hangge.com</h1>,
      document.getElementById('example')
    );
</script>
2. 外聯(lián)方式載入

即將 JSX 代碼單獨(dú)放在一個(gè).jsx 文件中。

ReactDOM.render(
     <h1>hello hangge.com</h1>,
     document.getElementById('example')
);

然后在頁面上通過下面的方式引入這個(gè) .jsx 文件。

<script type="text/babel" src="hello.jsx"></script>


四、在 JSX 中使用表達(dá)式

可以任意地在 JSX 當(dāng)中使用 JavaScript 表達(dá)式,在 JSX 當(dāng)中的表達(dá)式要包含在大括號里(個(gè)人理解就是寫在JS里的HTML里的JS需要{}大括號)。

// 定義一個(gè)函數(shù),返回傳入的名字的拼寫后的結(jié)果
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}
// 定義一個(gè)數(shù)據(jù)類型為對象的常量
const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};
// 使用JSX語法來定義一個(gè)html標(biāo)簽(所以element為小寫開頭)
const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);
// 渲染這個(gè)html標(biāo)簽
ReactDOM.render(
  element,
  document.getElementById('root')
);

注意:

  1. 我們書寫 JSX 的時(shí)候一般都會帶上換行和縮進(jìn),這樣可以增強(qiáng)代碼的可讀性。
  2. 與此同時(shí),我們同樣推薦在 JSX 代碼的外面擴(kuò)上一個(gè)小括號,這樣可以防止 分號自動插入 的 bug。


五、JSX 本身其實(shí)也是一種表達(dá)式

在編譯之后呢,JSX 其實(shí)會被轉(zhuǎn)化為普通的 JavaScript 對象。

這也就意味著,你其實(shí)可以在 if 或者 for 語句里使用 JSX,將它賦值給變量,當(dāng)作參數(shù)傳入,作為返回值都可以:

// 定義一個(gè)函數(shù),如果有傳參數(shù)進(jìn)來就把名字拼寫好返回,否則就返回陌生人
function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}


六、JSX 屬性

  • 你可以使用引號來定義以字符串為值的屬性:
const element = <div tabIndex="0"></div>;
  • 也可以使用大括號來定義以 JavaScript 表達(dá)式為值的屬性:
const element = <img src={user.avatarUrl}></img>;

切記使用了大括號包裹的 JavaScript 表達(dá)式時(shí)就不要再到外面套引號了。JSX 會將引號當(dāng)中的內(nèi)容識別為字符串而不是表達(dá)式。(不要src="{user.avatarUrl}",會以為src為{user.avatarUrl})


七、JSX 嵌套

如果 JSX 標(biāo)簽是閉合式的,那么你需要在結(jié)尾處用/>, 就好像 XML/HTML 一樣:

const element = <img src={user.avatarUrl} />;

JSX 標(biāo)簽同樣可以相互嵌套:(當(dāng)換行和縮進(jìn)的時(shí)候,使用括號包住它們)

const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

警告:
因?yàn)?JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小駝峰命名 來定義屬性的名稱,而不是使用 HTML 的屬性名稱。(概括就是: JSX使用小駝峰命名定義屬性的名稱)
例如,class 變成了 className,而 tabindex 則對應(yīng)著 tabIndex。


八、JSX 防注入攻擊

你可以放心地在 JSX 當(dāng)中使用用戶輸入:

const title = response.potentiallyMaliciousInput;
// 直接使用是安全的:
const element = <h1>{title}</h1>;

React DOM 在渲染之前默認(rèn)會 過濾 所有傳入的值。它可以確保你的應(yīng)用不會被注入攻擊。所有的內(nèi)容在渲染之前都被轉(zhuǎn)換成了字符串。這樣可以有效地防止 XSS(跨站腳本) 攻擊。

九、HTML 轉(zhuǎn)義

React 會將所有要顯示到 DOM 的字符串轉(zhuǎn)義,防止 XSS。所以如果 JSX 中含有轉(zhuǎn)義后的實(shí)體字符比如 &copy; (?) 最后顯示到 DOM 中不會正確顯示,因?yàn)?React 自動把 &copy; 中的特殊字符轉(zhuǎn)義了。有幾種解決辦法:

  • 直接使用 UTF-8 字符 ?
  • 使用對應(yīng)字符的 Unicode 編碼,查詢編碼
  • 使用數(shù)組組裝 <div>{['cc ', <span>&copy;</span>, ' 2015']}</div>
  • 直接插入原始的 HTML
<div dangerouslySetInnerHTML={{__html: 'cc &copy; 2015'}} />


十、JSX 代表 Objects

Babel 轉(zhuǎn)譯器會把 JSX 轉(zhuǎn)換成一個(gè)名為React.createElement()的方法調(diào)用。

下面兩種代碼的作用是完全相同的:

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

React.createElement() 這個(gè)方法首先會進(jìn)行一些避免bug的檢查,之后會返回一個(gè)類似下面例子的對象:

// 注意: 以下示例是簡化過的(不代表在 React 源碼中是這樣)
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world'
  }
};

這樣的對象被稱為 “React 元素”。它代表所有你在屏幕上看到的東西。
React 通過讀取這些對象來構(gòu)建 DOM 并保持?jǐn)?shù)據(jù)內(nèi)容一致。

十一、注釋

在 JSX 里使用注釋也很簡單,就是沿用 JavaScript,唯一要注意的是在一個(gè)組件的子元素位置使用注釋要用 {} 包起來。

var content = (
  <Nav>
      {/* child comment, put {} around */}
      <Person
        /* multi
           line
           comment */
        name={window.isLoggedIn ? window.name : ''} // end of line comment
      />
  </Nav>
);


十二、自定義 HTML 屬性

如果在 JSX 中使用的屬性不存在于 HTML 的規(guī)范中,這個(gè)屬性會被忽略。如果要使用自定義屬性,可以用 data- 前綴。

可訪問性屬性的前綴 aria- 也是支持的。

支持的標(biāo)簽和屬性

如果你要使用的某些標(biāo)簽或?qū)傩圆辉谶@些支持列表里面就可能被 React 忽略,必須要使用的話可以提 issue,或者用前面提到的 dangerouslySetInnerHTML。

十三、屬性擴(kuò)散

有時(shí)候你需要給組件設(shè)置多個(gè)屬性,你不想一個(gè)個(gè)寫下這些屬性,或者有時(shí)候你甚至不知道這些屬性的名稱,這時(shí)候 spread attributes 的功能就很有用了。

比如:

var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;

props 對象的屬性會被設(shè)置成 Component 的屬性。

屬性也可以被覆蓋:

ar props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'

寫在后面的屬性值會覆蓋前面的屬性。

關(guān)于 ... 操作符
The ... operator (or spread operator) is already supported for arrays in ES6. There is also an ES7 proposal for Object Rest and Spread Properties.


參考資料

  1. React 官方中文文檔
  2. React 中文文檔
  3. React - JSX語法詳解(附樣例)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 3. JSX JSX是對JavaScript語言的一個(gè)擴(kuò)展語法, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,979評論 0 24
  • 原文地址:Learning React.js is easier than you think原文作者:Samer...
    sunshine小小倩閱讀 4,341評論 3 41
  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時(shí),對React的特性、重點(diǎn)和注意事項(xiàng)的提取、精練和總結(jié),可以做為React特性...
    科研者閱讀 8,409評論 2 21
  • JSX是React的核心組成部分,它使用XML標(biāo)記的方式去直接聲明界面,界面組件之間可以互相嵌套??梢岳斫鉃樵贘S...
    可樂愛上咖啡閱讀 72,334評論 1 63
  • 宏圖偉業(yè)志興邦,立校江濱育棟梁。 閱盡書山尋正道,辨明真理覓圖強(qiáng)。 百年積淀何其重,一脈傳承自可彰。 翠瓦紅磚銘舊...
    半畝田叟閱讀 519評論 0 1

友情鏈接更多精彩內(nèi)容