JSX 與 HTML 的差異:5 個常見新手錯誤一次搞懂

更新日期: 2025 年 3 月 30 日

當你開始學習 React 時,第一個遇到的語法通常就是 JSX

它看起來很像 HTML,但實際上是 JavaScript 的一部分。這種「像 HTML 的 JavaScript」語法雖然直覺、易讀,卻也常常讓初學者混淆。

本篇文章將帶你認識 JSX 與 HTML 的差異,並透過「5 個常見新手錯誤」來幫助你避開陷阱、順利寫出正確的 React 元件!


class 不能用了?用 className 才對!

當你從 HTML 轉換到 JSX 時,第一個會撞到的牆,通常就是這個:

為什麼明明在 HTML 裡寫了無數次的 class="...",到了 JSX 卻會出錯?

⛔ 錯誤用法(HTML 習慣)

<div class="container"></div>

✅ 正確寫法(JSX 規則)

<div className="container"></div>

為什麼不能用 class

這是因為在 JavaScript 語言本身中,class 是保留字(reserved keyword),用來定義類別,例如:

class Person {
  constructor(name) {
    this.name = name
  }
}

JSX 雖然看起來像 HTML,但實際上是 JavaScript 的語法擴充(語法糖),最終會被編譯成 JavaScript 函式呼叫。

所以當你在 JSX 裡寫 <div class="container">,JavaScript 會搞不清楚你是想定義一個類別還是給元素加上樣式 class,導致語法錯誤。

為了避免這個衝突,React 特別設計了替代屬性名稱 className,來代表 HTML 中的 class 屬性。

✅ 實際範例:如何正確為 JSX 元素加上 class

function App() {
  return (
    <div className="box active">
      <h1 className="title">歡迎來到 React 世界!</h1>
    </div>
  )
}

在這個範例中,我們為 divh1 加上了多個 class,完全依照我們過去寫 HTML 的習慣,只是將 class 改成了 className

常見誤解:那 className 是 HTML 的標準嗎?

不是。

className 並不是 HTML 的標準屬性,它是 React 專門為 JSX 設計的對應屬性

它在被 React 處理後,最終仍會變成標準 HTML 的 class

<div className="container"></div>

會被轉換成:

<div class="container"></div>

所以瀏覽器看到的還是熟悉的 HTML 格式,不用擔心。

📌 小提醒與實戰建議

  • 千萬不要混用:你可能會想「我改一半先試試看」,但 class 在 JSX 裡是錯誤語法,會直接報錯,甚至導致整個組件無法渲染。
  • VSC 或 IDE 提示:現代開發工具大多會直接提醒你 class 是錯誤屬性,並建議使用 className,學會接受這個錯誤訊息是新手的重要一步。
  • 記憶口訣「JSX 用 JavaScript 語法,class 要改 className」

style 要改寫成物件,而且要駝峰命名

在寫 HTML 時,我們習慣使用類似 CSS 的語法,把 style 寫成一整段字串。

但到了 JSX 裡,這樣的寫法會造成錯誤,因為 JSX 背後是 JavaScript,寫法也就必須符合 JavaScript 的邏輯。

⛔ 錯誤用法(HTML 習慣)

<div style="background-color: red; font-size: 16px;"></div>

這種寫法在 HTML 裡沒問題,但放到 JSX 裡會報錯!

✅ 正確寫法(JSX 規則)

<div style={{ backgroundColor: 'red', fontSize: '16px' }}></div>

看起來是不是有點奇怪?雙層大括號?屬性也變得怪怪的?

別擔心,下面一步一步解釋給你聽。

為什麼直接寫字串不行?因為 JavaScript 的 style 本來就不是字串!

當你在 JSX 裡寫這樣的程式碼:

<div style="color: red;"></div>

React 會將它轉譯為:

React.createElement('div', { style: 'color: red;' })

你會以為你只是幫這個 <div> 加上紅色字體,但實際上,你是在 JavaScript 中把一段字串傳給 style 屬性。

問題來了:在 JavaScript 的世界裡,style 這個屬性本身不是用來接收字串的,而是 DOM 中一個特殊的物件,叫作 CSSStyleDeclaration

也就是說,你不能對它傳一段字串,它不會自己解析成 CSS,而是要一個個屬性設定。

📌 JavaScript 中操作樣式的正確方式:物件屬性設定

我們來看一個更具體的例子:

const div = document.createElement('div')   // 建立一個 <div> 元素
div.style.color = 'red'                     // 設定文字顏色
div.style.fontSize = '16px'                 // 設定文字大小

這段程式碼完全不需要字串拼接,它是直接使用 style 屬性上面的每個樣式鍵,像是 .color.fontSize,逐一賦值來完成樣式設定。

換句話說,style 其實是一個JavaScript 物件,你對它操作的方式,是用「屬性」的方式而不是「一段字串」。

🔄 對應到 React:JSX 是 JavaScript,當然也要用物件

React 就是遵守這個原則,當你在 JSX 裡寫樣式的時候,style 屬性也被設計成接受 JavaScript 物件。

所以正確的 JSX 寫法是:

<div style={{ color: 'red', fontSize: '16px' }}></div>

React 背後會根據這個物件的每個 key-value,呼叫 DOM 的 element.style.xxx = ... 一一套用,結果和你用 div.style.color = 'red' 是一樣的效果。

🤓 小知識補充:style="..." 在瀏覽器裡是例外機制

你可能會想問:「可是在 HTML 裡寫 style="..." 不是很好用嗎?」

這是因為 HTML 文件格式被瀏覽器特別設計來「容許你寫一整段 CSS 字串」,所以它可以解析:

<div style="background-color: blue; font-size: 18px;"></div>

但你一旦進入 JavaScript,特別是在 React 的 JSX 中,這種方便的機制就不再適用,而是回歸 JavaScript 本身的標準語法,也就是「使用物件、逐一賦值」的方式來設定樣式。

正確寫法:傳入 JavaScript 樣式物件

React 要求你將 style 寫成 JavaScript 的物件格式,像這樣:

<div style={{ color: 'red', fontSize: '16px' }}></div>

是不是看到兩層大括號覺得有點奇怪?

來拆解一下它的結構:

  • 外層 { ... }:代表這是一段 JavaScript 表達式(JSX 語法)
  • 內層 { ... }:是實際的樣式物件(JavaScript 的 Object)

這樣 React 就可以把你傳進去的物件,正確地對應到 DOM 元素的樣式屬性,最終產生出對應的 CSS:

<div style="color: red; font-size: 16px;"></div>

✅ 實戰範例:把 HTML 寫法改成正確的 JSX 寫法

功能HTML 寫法JSX 寫法
背景顏色 + 字體大小style="background-color: red; font-size: 16px;"style={{ backgroundColor: 'red', fontSize: '16px' }}
粗體文字style="font-weight: bold;"style={{ fontWeight: 'bold' }}
邊框樣式style="border: 1px solid black;"style={{ border: '1px solid black' }}

💡延伸:style 也可以用變數管理

為了讓樣式更清楚、可重用,你也可以把樣式物件存在變數裡:

const boxStyle = {
  backgroundColor: 'lightblue',
  padding: '10px',
  borderRadius: '8px'
}

function App() {
  return <div style={boxStyle}>Hello, styled box!</div>
}

這樣寫會讓組件更清晰、方便維護。


JSX 中只能回傳一個根元素(Single Root Element)

在寫 React 元件時,很多初學者常會遇到這樣的錯誤狀況:

⛔ 錯誤寫法:想回傳多個標籤

return (
  <h1>Hello</h1>
  <p>World</p>
)

這樣寫在 HTML 中完全合理,畢竟瀏覽器可以解析一串 <h1><p> 並正常渲染。但在 JSX 中,這樣會直接導致語法錯誤!

🤔 錯在哪裡?JSX 不允許「平行元素」

React 中的 JSX 語法有一個基本規則:

每個元件的 return 語法中,只能回傳 一個單一的最外層元素(root element)

換句話說,上面的寫法 React 會這樣理解:

return [
  React.createElement('h1', null, 'Hello'),
  React.createElement('p', null, 'World')
]

但這會讓 React 搞不清楚「這兩個元素誰是根元素」,就像一棟房子如果有兩個地基,React 不知道要從哪一個開始蓋,結果就是報錯。

✅ 正確做法:用容器把多個元素包起來

你只要用一個包覆元素(wrapper element)把所有東西包起來,就可以滿足「只有一個根元素」的規則。最常見的做法是用 <div>

return (
  <div>
    <h1>Hello</h1>
    <p>World</p>
  </div>
)

這樣就成功了!因為現在整個 return 回傳的東西,只有一個根 <div>,裡面再包著兩個子元素。

替代方案:使用 React Fragment(不產生多餘的 DOM)

有時候你只想要包起來,但又不想真的多一層 <div> 出現在畫面中(避免產生不必要的 DOM 結構),這時可以使用 React Fragment

return (
  <>
    <h1>Hello</h1>
    <p>World</p>
  </>
)

這裡的 <></>Fragment 的縮寫語法,它不會被渲染成任何 HTML 元素,但能夠達到「包住多個元素」的效果。

你也可以寫成完整語法:

return (
  <React.Fragment>
    <h1>Hello</h1>
    <p>World</p>
  </React.Fragment>
)

兩者功能完全一樣,差別只在語法形式。縮寫語法更簡潔、常用於日常開發。

📌 小提醒與實務建議

  • 每一個 JSX return 的最外層只能有一個元素,這是語法規定,不是選擇。
  • 若只是為了包住多個元素但又不想污染 DOM 結構,建議使用 <>...</>(Fragment)。
  • Fragment 在元件層級管理時很有用,例如在列表、條件渲染中,能保持結構簡潔。

實際對比:多個元素回傳方式比較

寫法是否正確是否會產生多餘 DOM
多個元素平行 return❌ 錯誤
使用 <div> 包住✅ 正確✅ 會產生 <div>
使用 Fragment 包住✅ 正確❌ 不會產生 DOM 元素

屬性命名要用駝峰式(camelCase)

⛔ 錯誤寫法:照抄 HTML 的寫法會出錯

許多初學者在寫 JSX 的時候,會直覺地把 HTML 裡熟悉的事件寫法搬過來,例如:

<input type="text" onclick="handleClick()" />

這在 HTML 裡的意思是:當使用者點擊這個輸入框時,執行 handleClick() 這個函式。

沒問題,瀏覽器可以解析這段字串並觸發對應的 JavaScript 函式。

但在 React 中,這樣寫會直接報錯或根本沒有效果,原因是 JSX 背後的運作邏輯和 HTML 完全不同。

🤔 為什麼這樣寫會錯?來看 React 如何轉譯這段程式碼

React 並不是直接將 JSX 原封不動地呈現在畫面上,而是先把 JSX 編譯(轉譯)成 JavaScript 的函式呼叫,像這樣:

⛔ 錯誤寫法:

<input type="text" onclick="handleClick()" />

React 背後的轉譯結果:

React.createElement('input', {
  type: 'text',
  onclick: 'handleClick()'
})

分析一下這裡出了什麼問題:

  1. 事件屬性名稱是錯的
    • HTML 裡事件是小寫的 onclick,但在 JSX 中要遵守 JavaScript 的命名規則 → 駝峰式 onClick
    • 寫成 onclick,React 會把它當成「一般的屬性」,加在 DOM 上,根本不會綁定事件。
  2. 事件處理方式是錯的
    • 你傳進去的是一個字串 "handleClick()",React 不會主動執行這段字串(不像瀏覽器會解析 HTML)。
    • React 要求你傳入的是一個「JavaScript 函數參照」,而不是字串形式的程式碼。

✅ 正確寫法應該長這樣:

<input type="text" onClick={handleClick} />

正確寫法的 React 轉譯結果:

React.createElement('input', {
  type: 'text',
  onClick: handleClick
})

這就完全正確了!

  • onClick 是 JavaScript 中合法的屬性命名方式(駝峰式),React 能夠辨識這是一個事件處理器。
  • handleClick 是一個函數參照,等到使用者真的點擊時,React 才會幫你呼叫它。

還有哪些屬性也要用駝峰命名?

除了事件屬性之外,還有許多 HTML 常用屬性,在 JSX 裡都需要改寫成 JavaScript 風格:

HTML 屬性JSX 寫法說明
onclickonClick所有事件都要用駝峰式命名
tabindextabIndex控制鍵盤瀏覽順序
readonlyreadOnly設定為唯讀輸入
maxlengthmaxLength限制輸入字元數量
forhtmlFor<label> 元素專用(因為 for 是 JS 保留字)

📎 小提醒:函式不要加引號也不要加小括號!

這是另一個常見錯誤源頭:

錯誤寫法問題原因
"handleClick()"這是字串,React 不會執行它
{handleClick()}這是「立刻執行」,不是傳參考
{handleClick}✅ 正確!傳入函式參考,事件發生時才執行

JSX 中的內容是 JavaScript 表達式!

在 React 中,JSX 是用來描述 UI 結構的語法糖,看起來像 HTML,但其實它和 JavaScript 有著非常緊密的關係。

其中一個最關鍵的特色就是:你可以在 JSX 裡用一對大括號 {}插入 JavaScript 表達式,讓畫面根據資料動態改變!

什麼是「JavaScript 表達式」?

簡單來說,「表達式(expression)」就是可以計算出一個值的程式碼。舉例來說:

類型範例備註
變數name回傳變數的值
運算式a + b計算結果是一個值
條件運算isLoggedIn ? "歡迎" : "請登入"根據條件產生不同值
函式呼叫getUserName()回傳值會顯示在畫面上

這些都是「表達式」,也就是你可以安全地放進 JSX 中 {} 的內容。

✅ 如何插入變數?

你可以直接將變數插入到 JSX 裡的標籤中,像這樣:

const name = "Tom"

return <h1>Hello, {name}</h1>

📌 name 是一個變數,放在 {} 裡表示要插入它的值。這段程式會輸出:

<h1>Hello, Tom</h1>

✅ 如何插入運算式、條件判斷?

你也可以在 {} 裡使用三元運算子(ternary operator)做條件渲染:

const isLoggedIn = true

return (
  <p>{isLoggedIn ? "歡迎回來" : "請先登入"}</p>
)

📌 如果 isLoggedIntrue,則顯示「歡迎回來」;否則顯示「請先登入」。

✅ 還可以做哪些事?

你可以用 {} 做任何「單行」的 JavaScript 計算或邏輯操作,例如:

<h2>總金額:{price * quantity}</h2>
<p>現在時間:{new Date().toLocaleTimeString()}</p>

不能放什麼?

雖然 {} 可以插入 JavaScript 表達式,但有一些東西是不能放進去的,會造成語法錯誤或邏輯錯誤:

🚫 控制語句(statements)

// 錯誤寫法
<p>{if (isLoggedIn) { return "Hi" }}</p>

控制語句像是 ifforwhile 等,屬於「程式流程控制語句」,不是表達式,不能放在 {} 裡。

🚫 多行程式碼區塊

// 錯誤寫法
<p>{
  const name = "Tom"
  name.toUpperCase()
}</p>

這樣的多行語句會讓 JSX 編譯器無法判斷你的意圖,因為 {} 只接受「一行能產出值的表達式」。

✅ 正確處理方式:把邏輯寫在 JSX 外

如果你需要條件判斷、變數處理等邏輯,請先寫在 JSX 外面,然後只在 JSX 中插入最終結果:

let message
if (isLoggedIn) {
  message = "歡迎回來"
} else {
  message = "請先登入"
}

return <p>{message}</p>

或者使用三元運算子(表達式)直接寫在 JSX 裡:

<p>{isLoggedIn ? "歡迎回來" : "請先登入"}</p>

總結一下

可用在 JSX {} 中的❌ 不可用的
變數if、for、while 等語句
運算式多行邏輯區塊或大括號程式碼
函式呼叫任何無法直接產出值的語句
三元運算子

結語:記住這 5 點,新手錯誤不再犯!

雖然 JSX 看起來像 HTML,但它本質上是 JavaScript 的延伸,所以寫法上有許多不一樣的地方。

只要記住以下 5 點,就能大幅減少踩雷機會:

  1. className 取代 class
  2. style 寫成物件 + 駝峰命名
  3. 每個 return 只能有一個根元素
  4. 所有屬性與事件皆需駝峰命名
  5. {} 插入 JavaScript 表達式(不是語句)

學會這些小技巧,你就能更順利地掌握 React 的基礎,讓寫元件變得更有信心!

Similar Posts