iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 3
1
Modern Web

I Want To Know React系列 第 3

I Want To Know React - 初探 JSX

簡介 JSX

JSX 全名為 JavaScript XML,是一種 JavaScript 的擴充語法,支援在 JavaScript 中撰寫 HTML-like/XML-like 的程式。與 HTML 的功能相似,JSX 也是用來定義畫面上的 Element,這些 JSX 產生的 Element 會在 React render 的階段被顯示到畫面上。

除了能把 Element 寫在 JavaScript 這點外,JSX 的 Element 語法和 HTML 幾乎相同,讓我們來看看範例:

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

其他常見的 HTML 語法也能舉一反三到 JSX 上,舉例來說,Element 可以有 children、可以有 attribute、可以直接 close tag:

// JSX can have children elements
<div><h1>Hello, Henry</h1></div>;

// JSX can have attribute and can use close tag
<img src="https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-260nw-1048185397.jpg" alt="Oops" className="greeting-picture" />

其實 JSX 在 React 中並不是必須的。開發者可以撰寫純 JavaScript 做到與 JSX 一樣的功能,但由於使用 JSX 可以有效提升 React 中 UI 部分的可讀性,因此官方十分推薦使用 JSX 開發 React,這也是大多數開發者在使用 React 時的標準配備。

讀到這裡,初次接觸的讀者也許會很疑惑為何 React 要將 HTML 語法寫在 JavaScript 中,而不拆分為一般的樣板與邏輯就好呢?下面就來探究一下原因吧!

Why JSX?

從上述的簡介可以知道,JSX 與其他框架(Angular、Vue)所採用的樣板語法有很大的區別。JSX 把 UI 的骨架(template)與 UI 的資料、邏輯(view modal / logic)都放到 JavaScript 中一起撰寫,而非把這兩個部分分開來寫。

究竟為何 React 要把 template 與 logic 寫在一起呢?這樣不就沒有關注點分離了嗎?這樣做的優點是甚麼?而使用 JSX 到底又可以帶我們甚麼好處呢?

針對這些問題,React 團隊給出的理由是:希望能達到更合適的 "高內聚低耦合High cohesionLow coupling)"。

元件內的高內聚(High cohesion)

React 認為 template 與 view modal 其實是強烈耦合的,時常會讓關注點難以分離。

舉例來說,template 與 view modal 的內容時常是密不可分的。View modal 中常常會有一些專為 template 而生的內容(例如顏色、class name...etc)。由於這些資料是 template 專用,因此改動 view modal 中的資料其實幾乎等同於改動 template。template 與 view modal 之間模糊的邊界甚至會導致一些弔詭的現象,例如有時必須修改 view modal 才可以達到改畫面樣式的需求。

反之亦然,view modal 有時候會有顯示資料處理的相關邏輯(例如是否顯示、排序...etc),這些邏輯常常也是能夠被寫在 template 中的。這代表,當在閱讀程式時,我們既可能在 template 中尋找這段邏輯,但也可能需要到 view modal 中去找。當專案與畫面規模變大或沒有規範良好的 coding style 時,這些兩頭找的情境就會帶來開發上的負擔。

因此 React 團隊把這個問題重新思考,他們認為既然 template 與 view modal 如此強烈耦合,與其把他們分開看待,那不如當作一體一起操作。這就是為何 React 團隊會把 template 與 view modal 融合為 JSX 的原因。

我們應該把關注點放在完整個 UI 元件上,而非把他分離成 UI 的畫面與 UI 的邏輯。

元件間的低耦合(Low coupling)

相較於 template 與 view modal 的分離,React 認為更應該把解藕點放在每個 UI 元件(Component)之間。

如同 Atomic Design 的概念,我們可以把一個頁面(page)看待成多個小元件堆疊起來的大區塊,而每個小元件都應該是要可以被複用的,這也讓 UI 設計與程式開發皆可達到更高的一致性與開發效率。

以程式開發面來說還有另一個優點,就是分離與解藕 Component 之間的關注點,使開發一個 Component 時不需要擔心會改壞另一個完全不相關的 Component 的程式!

到現在為止,我們已經知道了 What is JSX 與 Why JSX 了,接下來就窺探一下 JSX 底下的內部原理吧!

JSX 內部原理

JSX 為何能被執行的?

如前面段落所提,JSX 是 JavaScript 的擴充語法,而非原生的 JavaScript,因此瀏覽器是看不懂 JSX 的。因此在執行 JSX 之前其實還有一個很重要的步驟:利用 Babel 將 JSX 轉譯回原生的 JavaScript,如此一來瀏覽器就可以理解這些程式碼的內容了!

那 JSX 被轉譯成 JavaScript 後的內容到底會是什麼樣子呢?

JSX 轉譯成 JavaScript 後的樣子

當 JSX 被轉譯成 JavaScript 後就會變成以下這個函式執行:

React.createElement(
  type,
  [props],
  [...children]
)

可以看到這其實就是 React 提供的函式:createElement。實際上 JSX 並沒有提供什麼複雜的 "魔法",他就只是一個 JavaScript 的執行函式而已。接下來就讓我們來詳細了解一下 createElement API。

React.createElement 的參數有三個:

  • type:Element 的 type (如 div span ...etc)
  • props:Element 的 props,即 attribute (如 className src ...etc)
  • children:Element 的 children,就是包在 Element 內的子 Element,第三個以下的參數都代表 children

React.createElement 的回傳值如下:

  • reactElement:為一種 JavaScript Object,包含了 JSX Element 中的相關屬性 (如 type props ...etc)。在 React 中,我們把 createElement 所回傳的 JavaScript Object 稱為 React Element

就來看一個 JSX 轉為 JavaScript 後的範例吧:

// This is a JSX element
const jsxElement = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

// it equals to this
const jsElement = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

// and the truth is, React elements are just JavaScript Objects
console.log(jsxElment);
// {
//   type: 'h1',
//   props: {
//     className: 'greeting',
//     children: 'Hello, world!'
//   }
//   ...
// };

如果想要嘗試 JSX 轉譯後會長怎麼樣的話也可以到 Babel 提供的 Playground 中試看看。

JSX 執行後即為 JavaScript Object

由上可知,JSX 轉譯後會變成 JavaScript 的語法:React.createElement(),而 React.createElement() 執行又會回傳 JavaScript Object,也就是說,我們可以把 JSX 當作一個 JavaScript Object 看待。

當我們把 JSX 當作是 JavaScript Object 後,我們就能夠清楚的理解 JSX 的特性了。執行後的 JSX 擁有 JavaScript Object 的所有功能,因為 JSX 執行後其實就是 JavaScript Object。對 React Element(JSX Element)賦值、取值、取 property 等,都是完全合法的語法。

JSX 並不是魔法,它只是一項把擴充語法轉譯為原生語法的小魔術而已。"Everything is JS",這大概就是我們在寫 JSX 時最需要銘記在心的事情了。

小結

在這個章節中,我們已經瞭解 JSX 是甚麼了:

除此之外,也知道了 JSX 底下的內部原理:

  • JSX 其實是 React createElement() API 的語法糖
  • 執行後的 JSX 其實就是 JavaScript Object

下個章節中,我們將更詳細的介紹 JSX 的語法。

參考資料


上一篇
I Want To Know React - 初探 React
下一篇
I Want To Know React - JSX 語法
系列文
I Want To Know React30

尚未有邦友留言

立即登入留言