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

一闲延、什么是JSX

使用JSX聲明一個變量(React 當中的元素):

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

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

二癣漆、為什么要使用JSX

傳統(tǒng)的 MVC 是將模板放在其他地方,比如 <script> 標簽或者模板文件渠啤,再在 JS 中通過某種手段引用模板狐肢。按照這種思路,想想多少次我們面對四處分散的模板片段不知所措沥曹?糾結模板引擎份名,糾結模板存放位置碟联,糾結如何引用模板……下面是一段 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 認為組件才是王道僵腺,而組件是和模板緊密關聯(lián)的鲤孵, JSX 這種語法,就是為了把HTML模板直接嵌入到JS代碼里面辰如,這樣就做到了模板和組件關聯(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 代碼單獨放在一個.jsx 文件中豌蟋。

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

然后在頁面上通過下面的方式引入這個 .jsx 文件廊散。

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


四、在 JSX 中使用表達式

可以任意地在 JSX 當中使用 JavaScript 表達式梧疲,在 JSX 當中的表達式要包含在大括號里(個人理解就是寫在JS里的HTML里的JS需要{}大括號)允睹。

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

注意:

  1. 我們書寫 JSX 的時候一般都會帶上換行和縮進往声,這樣可以增強代碼的可讀性擂找。
  2. 與此同時,我們同樣推薦在 JSX 代碼的外面擴上一個小括號浩销,這樣可以防止 分號自動插入 的 bug贯涎。


五、JSX 本身其實也是一種表達式

在編譯之后呢慢洋,JSX 其實會被轉化為普通的 JavaScript 對象塘雳。

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

// 定義一個函數(shù)太防,如果有傳參數(shù)進來就把名字拼寫好返回妻顶,否則就返回陌生人
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 會將引號當中的內(nèi)容識別為字符串而不是表達式讳嘱。(不要src="{user.avatarUrl}",會以為src為{user.avatarUrl})


七酿愧、JSX 嵌套

如果 JSX 標簽是閉合式的沥潭,那么你需要在結尾處用/>, 就好像 XML/HTML 一樣:

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

JSX 標簽同樣可以相互嵌套:(當換行和縮進的時候,使用括號包住它們)

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

警告:
因為 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小駝峰命名 來定義屬性的名稱嬉挡,而不是使用 HTML 的屬性名稱钝鸽。(概括就是: JSX使用小駝峰命名定義屬性的名稱)
例如汇恤,class 變成了 className,而 tabindex 則對應著 tabIndex拔恰。


八因谎、JSX 防注入攻擊

你可以放心地在 JSX 當中使用用戶輸入:

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

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

九饭冬、HTML 轉義

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

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


十炊苫、JSX 代表 Objects

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

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

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

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

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

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

十一唠梨、注釋

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

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ī)范中盖灸,這個屬性會被忽略蚁鳖。如果要使用自定義屬性,可以用 data- 前綴赁炎。

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

支持的標簽和屬性

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

十三、屬性擴散

有時候你需要給組件設置多個屬性松邪,你不想一個個寫下這些屬性坞琴,或者有時候你甚至不知道這些屬性的名稱,這時候 spread attributes 的功能就很有用了逗抑。

比如:

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

props 對象的屬性會被設置成 Component 的屬性剧辐。

屬性也可以被覆蓋:

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

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

關于 ... 操作符
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語法詳解(附樣例)
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市荧关,隨后出現(xiàn)的幾起案子溉奕,更是在濱河造成了極大的恐慌,老刑警劉巖忍啤,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件加勤,死亡現(xiàn)場離奇詭異,居然都是意外死亡同波,警方通過查閱死者的電腦和手機鳄梅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來未檩,“玉大人戴尸,你說我怎么就攤上這事≡┙疲” “怎么了孙蒙?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長悲雳。 經(jīng)常有香客問我挎峦,道長,這世上最難降的妖魔是什么合瓢? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任坦胶,我火速辦了婚禮,結果婚禮上歪玲,老公的妹妹穿的比我還像新娘迁央。我一直安慰自己,他們只是感情好滥崩,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布岖圈。 她就那樣靜靜地躺著,像睡著了一般钙皮。 火紅的嫁衣襯著肌膚如雪蜂科。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天短条,我揣著相機與錄音导匣,去河邊找鬼。 笑死茸时,一個胖子當著我的面吹牛贡定,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播可都,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缓待,長吁一口氣:“原來是場噩夢啊……” “哼蚓耽!你這毒婦竟也來了?” 一聲冷哼從身側響起旋炒,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤步悠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瘫镇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鼎兽,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年铣除,在試婚紗的時候發(fā)現(xiàn)自己被綠了谚咬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡尚粘,死狀恐怖序宦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情背苦,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布潘明,位于F島的核電站行剂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钳降。R本人自食惡果不足惜厚宰,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望遂填。 院中可真熱鬧铲觉,春花似錦、人聲如沸吓坚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽礁击。三九已至盐杂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哆窿,已是汗流浹背链烈。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挚躯,地道東北人强衡。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像码荔,于是被迫代替她去往敵國和親漩勤。 傳聞我的和親對象是個殘疾皇子感挥,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 3. JSX JSX是對JavaScript語言的一個擴展語法, 用于生產(chǎn)React“元素”锯七,建議在描述UI的時候...
    pixels閱讀 2,827評論 0 24
  • 原文地址:Learning React.js is easier than you think原文作者:Samer...
    sunshine小小倩閱讀 4,229評論 3 41
  • 以下內(nèi)容是我在學習和研究React時链快,對React的特性、重點和注意事項的提取眉尸、精練和總結域蜗,可以做為React特性...
    科研者閱讀 8,233評論 2 21
  • JSX是React的核心組成部分,它使用XML標記的方式去直接聲明界面噪猾,界面組件之間可以互相嵌套霉祸。可以理解為在JS...
    可樂愛上咖啡閱讀 71,952評論 1 64
  • 宏圖偉業(yè)志興邦袱蜡,立校江濱育棟梁丝蹭。 閱盡書山尋正道,辨明真理覓圖強坪蚁。 百年積淀何其重奔穿,一脈傳承自可彰。 翠瓦紅磚銘舊...
    半畝田叟閱讀 488評論 0 1