iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 3
1
Modern Web

React 30天系列 第 3

Day 03-其實我只是披著html的javascript(JSX)

前情提要:
昨天把工作室(環境)都打造好了。
大家還記得昨天的環境建置的許下的兩個願望嗎?

  • 把React的ES6語法轉成ES5
  • 把JSX轉成瀏覽器看得懂的語法

就是它!把JSX轉成瀏覽器看得懂的語法
到底什麼是JSX?
我們看看react的解釋

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

This funny tag syntax is neither a string nor HTML.
It is called JSX, and it is a syntax extension to JavaScript. We recommend using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript.

好,React説JSX只是javascript的擴展語法,我們透過JSX來描繪UI的形貌,但看起來他就是個html啊,來證明給我看吧。
這時候我們就要請出Babel好朋友幫我們把JSX打回原形

https://ithelp.ithome.com.tw/upload/images/20181009/20111595cLHlZSsElP.png

你誰啊???!!!
https://media.giphy.com/media/jquDWJfPUMCiI/giphy.gif

我還是左轉去寫Vue好了
React說等等,其實沒這麼難懂,Babel轉換過的JSX透過React.createElement產出React element,我們來看看裡面的參數需要什麼:(reference)

React.createElement(
  type,
  [props],
  [...children]
)
  • type: tag name string (如:'div'或'span'), React component(class或function)或React fragment
  • [props]: 屬性值
  • [...children]: 內容/子元素

什麼什麼什麼,你在說什麼我什麼都不懂
好的,我們對照babel處理前的JSX和babel處理後的javascript

// JSX
(<h1>Hello, world!</h1>)
// Babel轉換
React.createElement("h1", null, "Hello, world!");

翻譯蒟蒻:我要用React.createElmet這個方法建立一個h1元素,裡面沒有屬性值,但內容文字是Hello, world!

好像有點感覺了,那屬性值是什麼?可以加html的attribute嗎?
如果我想在我的h1元素加上class的話要怎麼處理呢?

// JSX
(<h1 className="title">Hello, world!</h1>)
// Babel轉換
React.createElement("h1", { className: "title" }, "Hello, world!");

翻譯蒟蒻:我要用React.createElmet這個方法建立一個h1元素,className為"title",內容文字是Hello, world!
加上id後,原本第二個參數是null,已經轉成{ className: "title" }

好像有點懂了!那如果我的html是巢狀元素(nesting element)呢?

// JSX
(<p id="motto">The struggle is <strong>real</strong>.</p>)

// Babel轉換
React.createElement(
  "p",
  { id: "motto" },
  "The struggle is ",
  React.createElement("strong", null, "real"),
  "."
);

大家可以看到我在content (The struggle is real.) 裡面加了strong元素想強調real這個詞,所以建立一個新元素。往後每增加一個element就要用一次React.createElement,有多少用多少,免費不用錢,長得醜就是了。
我想這也是官方推薦使用JSX的原因。

注意事項
不曉得大家有沒有注意到上面的className,其實它代表的就是html的class,因為class是ES6的保留字,為了避免混淆所以區分。

面對相同狀況的苦主之二還有label的for,for在javascript也是有特殊功能的,所以在JSX上用到的label for需替換成htmlFor

另外,React DOM使用camelCase作為屬性命名規範,所以像是tabindex="0",在JSX裡會變成tabIndex="0",寫JSX時請大家留意這點。但...凡事都有例外XD

The exception is aria-* and data-* attributes, which should be lowercased. For example, you can keep aria-label as aria-label.
來源:React-DOM Elements

以上就是另外需要注意的地方


延續前天我們建立的開發環境,測試的時候我有將最基本的React雛形貼上index.js內,來回顧一下:

import React from 'react';  //匯入react library
import ReactDOM from 'react-dom'; //匯入react-dom library

const App = () => {
  //小括號包起來的就是用JSX建立的React element
  return (
    <div>
      Hello World!
    </div>
  );
};

ReactDOM.render(<App/>, document.getElementById('app'));

昨天能夠順利把Hello World!印到頁面上多虧ReactDOM.render的幫忙。
react-dom提供了幾款與DOM相關的特定方法供開發者使用,render應該是最常見的一種。Reference

ReactDOM.render(element, container[, callback])

第一個參數是element,第二個參數是container,第三個callback。

  • element: <App/>
  • container: document.getElementById('app')

<App/>是誰? (⊙o⊙)
<App/>是React的component,這個component會回傳React element(也就是<div>Hello World!</div>),element完成了總要有個container(容器)放,我們就指定DOM上id名為app的element擔此大任。

那如果我今天不想用JSX呢?我們來改寫一次

import React from 'react';
import ReactDOM from 'react-dom';

const App = () => {
  return (
    React.createElement('div', null, 'Hello World!')
  );
};

ReactDOM.render(React.createElement(App, null), document.getElementById('app'));

等等!第一個React.createElement我懂,是來建立div element的,但第二個React.createElement(App, null, null)是什麼,我們剛剛有見過他嗎?上一段我們提到<App/>是React的component,然後現在是???
時間拉回一開始我們在說明React.createElement時......

React.createElement(
  type,
  [props],
  [...children]
)
  • type: tag name string (如:'div'或'span'), React component(class或function)或React fragment
  • ......

第一個參數type其實也可以放入React component,所以基本上下面兩句語法是可以理解是相同功能的,差異只在JSX是否介入。

// JSX
<App/>
// Babel轉換
React.createElement(App, null, null)

反過來想,使用React component是因為透過JSX處理才變成簡潔乾淨的吧!

至於component是什麼?怎麼用?這又是明天的故事了...


回顧今日

  • JSX只是javascript的擴充語法
  • React.createElement才是真正幫我們產出React Element的幕後功臣
  • 使用React.createElement所需的參數有三個(type, props, children)
    • type可以是:
      • tag name string (如:'div'或'span')
      • React component(class或function)
      • React fragment(本集未提,可參考)
    • props: 屬性值
    • children: 內容或子元素
  • 因為不是真正的html所以以下有幾點需要注意
    • class需轉成className
    • for需轉成labelFor
    • tabindex需轉成tabIndex
    • 不需轉成camelCase的例外:
      • aria-*
      • data-*

結語
再回顧一次JSX,覺得很多知識就跟拔絲地瓜一樣拔不完,只能慢慢累積了XD
如果有誤人子弟的地方還請大家指正,謝謝大家收看。

相關參考資料


上一篇
Day 02-打造個人工作室(開發環境建置)
下一篇
Day 04-React的靈魂角色(Components)
系列文
React 30天30

尚未有邦友留言

立即登入留言