iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
JavaScript

React 觀念架構:從js 基礎到Hook 底層邏輯 系列 第 8 篇

Day 8 JSX 不是 HTML!揭開 Babel 將 JSX 轉譯為 React.createElement 的面紗

  • 分享至 

  • xImage
  •  

在前面幾天,我們探討了記憶體、閉包、高階函數、非同步與 Event Loop。今天我們要來拆解 React 開發者每天都在寫、卻最容易被誤解的語法——JSX。

在前面幾天,我們探討了記憶體、閉包、高階函數、非同步與 Event Loop。今天我們要來拆解 React 開發者每天都在寫、卻最容易被誤解的語法——JSX。

一、 JSX 的本質:Babel 轉譯器在背後做了什麼?

瀏覽器完全看不懂 JSX。你在 React 專案中寫的 JSX,在編譯打包階段,都會被 Babel(或 SWC、Vite 等編譯工具)轉譯成純粹的 JavaScript 函數呼叫。

例如:

const element = (
  <h1 className="title" id="heading">
    Hello React!
  </h1>
);

經過 Babel 編譯後,會變成真正的 JavaScript:

// 舊版轉譯結果 (React 17 以前)
const element = React.createElement(
  'h1',
  { className: 'title', id: 'heading' },
  'Hello React!'
);

React.createElement 的三個參數:

  1. type(類型):HTML 標籤名稱(如 'h1'、'div')或是另一個 React 組件函數。
  2. props(屬性):包含所有傳入屬性(如 className、id、onClick)的物件。
  3. ...children(子節點):該節點內包含的文字或子元素。

二、 轉譯後的產物:React Element(物件)

React.createElement() 執行後,會回傳一個純粹的 JavaScript 物件,這就是 React Element(虛擬 DOM 節點的前身)。

如果你把 element 變數 console.log 印出來,會看到類似這樣的結構:

// 真正的 React Element 物件結構
{
  $$typeof: Symbol(react.element), // 常用於安全性防止 XSS 攻擊
  type: 'h1',
  props: {
    className: 'title',
    id: 'heading',
    children: 'Hello React!' // 子節點會放在 props.children
  },
  ref: null,
  key: null
}

React 的工作,就是接收這個龐大的 JavaScript 物件樹(Virtual DOM),最後再交由 react-dom 渲染成真正的瀏覽器 DOM 節點。

三、 了解 JSX 本質後,秒懂的三大語法限制

當你明白「JSX 就是 React.createElement() 函數呼叫」後,React 許多看似無理的語法限制瞬間變得合情合理:

  1. 為什麼組件最外層只能有一個根節點 (Fragment)?
// ❌ 錯誤:無法回傳兩個獨立根節點
return (
  <h1>Title</h1>
  <p>Content</p>
);

// 等同於回傳兩個未封裝的函數呼叫,在 JS 中是語法錯誤 (SyntaxError):
// return React.createElement('h1') React.createElement('p');

解法:使用 <React.Fragment> 或簡寫 <> ... </> 包裹,這相當於建立一個容器來盛裝這組子元素。

  1. 為什麼屬性名稱是 className 而不是 class?
    因為 JSX 最終會轉譯為 JS 物件,而在 ES6 中,class 是 JavaScript 的保留字 (Reserved Word)(用於定義類別)。為了避免語法衝突與解析爭議,React 採用 DOM Property 的命名習慣(如 className、htmlFor)。

  2. 為什麼大括號 {} 裡面只能放「運算式 (Expression)」,不能放「語句 (Statement)」?

// ❌ 錯誤:不能在 {} 寫 if 語句
<div>{ if (isLoggedIn) { return <User />; } }</div>

// ✅ 正確:可以使用三元運算子 (運算式會回傳值)
<div>{isLoggedIn ? <User /> : <Guest />}</div>

原因:因為 {} 裡面的內容會直接被充當 React.createElement() 的參數。JavaScript 函數的參數位置只能放入有傳回值的「運算式」,不能放入如 if、for 或 switch 等「語句」。


上一篇
Day 07 Event Loop 機制:微任務 (Microtask) 與 React 批次更新
下一篇
Day 9 Virtual DOM 與 Reconciliation(協調算法):React 憑什麼那麼快?
系列文
React 觀念架構:從js 基礎到Hook 底層邏輯 共 15 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言