本文為 JSX 基礎介紹系列文:
- React 中的 JSX 是什麼?為什麼它長得像 HTML?
- JSX 與 HTML 的差異:5 個常見新手錯誤一次搞懂
- JSX 中如何插入 JavaScript?使用 {} 的基本原則
- JSX 中的條件渲染與清單渲染:實用範例教學
- JSX 背後的真相:它是怎麼轉換成畫面的?
閱讀完本系列文後,可以繼續閱讀《React 元件基礎介紹》介紹
當你開始學習 React 時,一定會遇到 JSX(JavaScript XML)這個概念。
它看起來像 HTML,卻不完全是 HTML,因為它的背後其實是 JavaScript!
JSX 允許你在畫面中以 HTML 語法描述 UI,同時,也能靈活地插入 JavaScript 程式碼,讓畫面根據資料動態變化。
但初學者常常會有疑問:我要怎麼在 JSX 裡插入 JavaScript 的變數、條件、函式呢? 答案是使用大括號 {}。
本文將詳細介紹這個用法,幫助你更自在地在 JSX 中操控 JavaScript 表達式。
基本原則:使用 {} 插入 JavaScript 表達式
在 JSX 中,只要你想在畫面上顯示 JavaScript 的值、運算結果或邏輯判斷,都必須使用大括號 {} 包住這段程式碼。
這個設計讓你可以在 HTML-like 的語法中靈活地動態顯示資料,或是根據程式邏輯控制畫面內容。
什麼可以放進 {}?
可以放的是 JavaScript 表達式(expression),而不是語句(statement)。
表達式 是會「產生一個值」的程式碼片段,例如:變數、運算、函式呼叫、三元運算子、陣列、物件等。
語句 則是做事情的程式碼,例如:
if判斷式、for迴圈、while等,這些不能放進{}。
舉個最簡單的例子,插入變數:
const name = '小明';
return <h1>Hello, {name}!</h1>;
輸出會是:
<h1>Hello, 小明!</h1>❌ 錯誤示範:放入語句(statement)
// 錯誤的寫法,JSX 不接受 if 語句直接放在 {} 中
return <div>{if (isOk) { return 'OK'; }}</div>;這段會直接報錯,因為 {} 裡面只能放會產生值的表達式,不能放像 if 這種語句。
✅正確方式:改用表達式
return <div>{isOk ? 'OK' : 'Not OK'}</div>;這裡的 isOk ? 'OK' : 'Not OK' 是一個表達式,會根據 isOk 的布林值來決定輸出內容,因此可以放進 JSX 裡。
延伸理解:JSX 背後是 React.createElement()
其實 JSX 只是語法糖,寫 JSX 的背後會被轉換成像這樣的原生 JavaScript:
const element = <h1>Hello, {name}!</h1>;
會轉成:
const element = React.createElement('h1', null, `Hello, ${name}!`);這就是為什麼只有能產生「值」的表達式能放進去,因為 JSX 的每一個 {} 最終都會變成 React.createElement 的參數值。
插入變數:顯示資料內容
在 JSX 中最基礎、也最常見的用法之一,就是插入變數。
當你有一筆資料儲存在變數裡,希望能顯示在畫面上時,就可以使用大括號 {} 把變數包起來,直接插入到你要呈現的地方。
基本範例:將變數插入 HTML 元素中
const age = 18;
return <p>年齡:{age}</p>;這段程式碼的意思是:建立一個段落 <p>,內容是「年齡:」後面接上變數 age 的值。畫面上看到的結果會是:
年齡:18🎯 背後邏輯:JSX = JavaScript + 標籤語法
這裡 age 是 JavaScript 中的變數,而 {age} 這段就是一個「JavaScript 表達式」,表示「把 age 的值拿出來插入到這個 <p> 標籤裡」。
由於我們使用 JSX,它可以混合 JavaScript 的語法來描述畫面,因此這樣的插入方式才成為可能。
變數值可以是什麼型別?
你可以插入各種 JavaScript 支援的基本資料型別,只要它們能被「顯示」在畫面上:
| 資料型別 | 能否插入 JSX? | 說明 |
|---|---|---|
字串 string | ✅ 可以 | 最常見,例如名字、標題、說明文字等 |
數字 number | ✅ 可以 | 用來顯示價格、年齡、數量等 |
布林值 boolean | ❌ 不建議直接插入 | true 或 false 會直接轉成字串顯示,不太直觀 |
| null、undefined | ❌ 不會顯示任何內容 | 這類值 JSX 會忽略,不會渲染 |
陣列 array | ✅ 可以,但需搭配 .map() 使用 | 常用來產生清單(會在下一段介紹) |
物件 object | ❌ 不可直接插入 | JSX 不知道怎麼顯示物件,會報錯 |
❌ 錯誤示範:插入物件
const user = { name: '小美', age: 20 };
// 錯誤寫法:物件不能直接放進 JSX 中
return <div>{user}</div>;
這樣會造成錯誤,因為 React 無法直接將物件轉為可顯示的內容。
✅ 正確方式應該是取出特定屬性:
return <div>{user.name},{user.age} 歲</div>;💡 實用小技巧:結合文字與變數
你可以在一段文字中混合變數與固定內容,非常適合用來呈現個人化的訊息:
const name = '小華';
const score = 95;
return <p>{name} 的成績是 {score} 分</p>;
輸出:
小華 的成績是 95 分延伸應用:插入變數到屬性中
不只是在標籤內容中,你也可以將變數插入到 HTML 標籤的屬性值中,一樣使用 {}:
const imgUrl = 'https://example.com/avatar.jpg';
return <img src={imgUrl} alt="使用者大頭貼" />;
這邊的 src={imgUrl} 就是讓 <img> 使用我們定義的變數來當作圖片來源。
插入函式呼叫:顯示運算後的結果
在 JSX 中,不只能插入變數,也可以插入函式的回傳值。
這讓我們能夠在畫面中呈現經過邏輯處理、格式化、計算過的結果,而不是單純的靜態資料。
這是讓畫面更「聰明」的重要技巧之一。
基本用法:呼叫一個函式並插入結果
function greet(name) {
return `你好,${name}`;
}
return <h2>{greet('小華')}</h2>;
在這段程式碼中,我們先定義了一個 greet() 函式,它會接收一個名字並回傳打招呼的字串。
接著,我們在 JSX 裡面使用 {greet('小華')} 呼叫這個函式,並把它的回傳值插入 <h2> 標籤中。結果畫面會顯示:
你好,小華什麼樣的函式可以插入?
只要是 會回傳值的函式,就可以插入到 JSX 中。
這些回傳值可以是:
| 回傳型別 | 說明 |
|---|---|
字串 (string) | 最常見,用來產生有格式的文字 |
數字 (number) | 可用於計算結果、統計數字等 |
| JSX 元素 | 可以回傳整個 <div>...</div> 或其他組件 |
| 陣列 | 通常配合 .map() 來動態產生清單 |
null | 用來不渲染任何東西(常見於條件渲染) |
🔧 範例 1:格式化數值
function formatPrice(price) {
return `$${price.toFixed(2)}`;
}
const price = 128;
return <p>價格:{formatPrice(price)}</p>;結果會顯示:
價格:$128.00這裡的 formatPrice 是一個「邏輯包裝」函式,把原始數字轉換成帶有 $ 且小數兩位的格式,這樣 JSX 裡的內容就能更符合真實情境。
🔧 範例 2:根據條件產生不同畫面
function getStatus(isOnline) {
return isOnline ? <span style={{ color: 'green' }}>在線</span> : <span style={{ color: 'gray' }}>離線</span>;
}
const isOnline = true;
return <p>狀態:{getStatus(isOnline)}</p>;
結果會渲染為一個彩色文字:「狀態:在線」,且綠色呈現。
這個技巧適用於更複雜的條件顯示,透過函式把「顯示邏輯」與「UI 呈現」做一點區隔,讓主畫面更清爽。
💡補充技巧:函式定義方式很多種
在 React 中,你可以用不同語法定義函式來供 JSX 使用,這裡列出三種常見方式:
1. 傳統函式
function greet(name) {
return `你好,${name}`;
}
2. 匿名函式配合變數
const greet = function(name) {
return `你好,${name}`;
};3. 箭頭函式(React 中最常見)
const greet = (name) => `你好,${name}`;你可以依照風格或團隊慣例選擇適合的方式。
常見錯誤:沒有 return 或函式沒回傳值
如果你的函式沒有回傳東西,或是少寫 return,插入到 JSX 中時就不會顯示任何內容,或顯示 undefined:
function greet(name) {
console.log(`你好,${name}`);
// ❌ 沒有 return
}
return <p>{greet('小花')}</p>; // 這裡不會顯示任何文字
✅ 修正方法:
function greet(name) {
return `你好,${name}`;
}
插入條件運算:動態改變內容
在網頁開發中,我們常常會遇到「根據條件顯示不同畫面」的情境,例如使用者是否登入、有沒有權限、資料是否加載完成等等。
在 JSX 中,我們無法直接使用傳統的 if 或 switch 語法(這些屬於語句 statement),但可以使用「條件運算子」與「邏輯運算子」這兩種方式,來實現畫面上的條件渲染。
為什麼不能用 if?
這是因為 JSX 的大括號 {} 只能插入「表達式(expression)」,而像 if、for 這些是「語句(statement)」,會造成語法錯誤。
// ❌ 錯誤:不能在 JSX 裡直接用 if
return (
<div>
{if (isLoggedIn) { return <p>歡迎回來!</p>; }}
</div>
);
正確方式 1:使用條件運算子(? :)
條件運算子(三元運算子)語法如下:
條件 ? 條件為真時的結果 : 條件為假時的結果這是一種能夠根據條件「選擇性產生內容」的表達式,非常適合用來插入 JSX 元素。
🔧 範例:根據登入狀態顯示不同訊息
const isLoggedIn = true;
return <p>{isLoggedIn ? '歡迎回來!' : '請先登入'}</p>;- 當
isLoggedIn為true,畫面顯示:「歡迎回來!」 - 當
isLoggedIn為false,畫面顯示:「請先登入」
你也可以插入完整的 JSX 元素,而不只是字串:
const isLoggedIn = false;
return (
<div>
{isLoggedIn ? (
<h2>歡迎進入會員中心</h2>
) : (
<button>點我登入</button>
)}
</div>
);
這讓我們可以根據狀態呈現完全不同的元件內容。
正確方式 2:使用邏輯 AND 運算子(&&)
當你只想在某個條件成立時顯示某一個內容,不需要處理「否則」的情況時,可以用 && 運算子。
條件 && 要顯示的內容
當條件為 true 時,才會顯示後面的內容;如果是 false,則什麼都不會顯示。
🔧 範例:有權限才顯示按鈕
const hasPermission = true;
return (
<>
<h3>功能列表</h3>
{hasPermission && <button>編輯</button>}
</>
);
如果 hasPermission 為 true,畫面會顯示按鈕 <button>編輯</button>;如果是 false,畫面就只會看到標題,不會有按鈕。
⚠️ 注意:布林值直接插入可能出現不預期結果
當你使用 && 來做條件顯示時,如果你插入的不是一個「JSX 元素」,而是某個 JavaScript 值(例如變數、數字、字串),它可能會直接被顯示出來,這通常不是你想要的結果。
🔍 例子:
const value = false;
return <p>{true && value}</p>;這裡 true && value 的結果是 false,因為 && 的運作規則是:
如果前面是
true,回傳後面的值;如果前面是
false,直接回傳false,不看後面。
所以實際上這段等於:
return <p>false</p>; // ⛔ 會把 false 當成文字印出來!這會在畫面上顯示「false」,這通常是錯誤或令人困惑的情況。
✅ 解法一:只渲染 JSX 元素
正確的做法是:當你使用 && 時,右邊的值應該是一個「JSX 元素」,也就是像 <p>...</p> 這樣的內容,而不是一般的變數或值。
const shouldShow = true;
return (
<>
{shouldShow && <p>這段文字會被顯示</p>}
</>
);
這樣寫沒問題,因為 <p>...</p> 是合法的 JSX 元素。
✅ 解法二:使用 !! 轉換成布林值
有時候你不確定變數的值是不是布林值(可能是 undefined、null、0、"" 等),但你只是想檢查「它是不是有值」,這時可以用 !! 強制轉換它為布林值。
🔧 什麼是 !!?
這是 JavaScript 裡的一個小技巧:
!!value
等同於:
Boolean(value)會把任何值轉成 true 或 false。轉換規則如下:
| 原始值 | !!後的結果 |
|---|---|
0 | false |
'' (空字串) | false |
null | false |
undefined | false |
false | false |
| 其他有內容的值 | true |
🔍 例子:避免渲染出非預期值
const commentCount = 0;
return (
<>
{/* 錯誤:會顯示 0 */}
{commentCount && <p>{commentCount} 則留言</p>}
{/* 正確:0 是 falsy,這段就不會顯示 */}
{!!commentCount && <p>{commentCount} 則留言</p>}
</>
);
第一行因為 commentCount 是 0,它雖然是 falsy,但仍然會被直接印出來;加上 !! 轉成布林值後,畫面上就不會顯示 0,而是完全不顯示這段 <p>。
🧠 延伸:條件運算子與邏輯運算子該用哪個?
| 使用場景 | 建議用法 |
|---|---|
| 根據條件「顯示 A 或 B」兩種可能 | ? :(條件運算子) |
| 根據條件「顯示或不顯示某項」 | &&(邏輯運算子) |
| 需要處理多重條件邏輯 | 抽成函式或組件處理 |
插入陣列:顯示清單
在實際開發中,我們常常需要根據一組資料清單,動態產生一組畫面內容,例如留言列表、產品卡片、待辦事項、選項按鈕等等。
在 JSX 中,我們通常會使用 JavaScript 的 陣列方法 .map() 來完成這件事,並搭配 {} 插入每一項轉換後的 JSX 元素。
基本範例:用陣列產生 <li> 清單
const fruits = ['蘋果', '香蕉', '芒果'];
return (
<ul>
{fruits.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
畫面上會顯示:
- 蘋果
- 香蕉
- 芒果
🎯 map() 是什麼?
.map() 是 JavaScript 陣列的內建方法,作用是:
把原本的陣列「一個一個拿出來」,經過你的函式處理後,「回傳一個新陣列」,每個元素是你轉換後的結果。
在 JSX 裡,我們就讓它回傳「一組 JSX 元素」,例如 <li>、<div>、自訂元件等等。
🔍 拆解每一行的意思
{fruits.map((item, index) => (
<li key={index}>{item}</li>
))}
fruits.map(...):針對陣列fruits中的每一個水果做處理。(item, index):每次處理時,會拿到陣列中的「值」與「索引」。<li>{item}</li>:回傳一個<li>元素,把每個水果的名稱顯示出來。key={index}:React 要求你為每個重複渲染的元素指定一個「唯一的 key」,幫助它在更新畫面時更有效率。
🔐 為什麼一定要加 key?
React 需要透過 key 來追蹤哪些項目被新增、刪除、重新排序。
如果你不加,React 會發出警告,並且可能導致效能問題或畫面錯亂。
最常見的做法是使用 index(索引值),但如果你有更穩定的 ID(像是資料庫提供的 id),建議使用真正的唯一值來當 key:
const users = [
{ id: 'u01', name: '小明' },
{ id: 'u02', name: '小美' },
];
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);🔁 實用範例:留言清單
const comments = [
{ id: 1, text: '第一則留言' },
{ id: 2, text: '這是第二則' },
{ id: 3, text: 'React 好好玩!' },
];
return (
<section>
<h2>留言列表</h2>
<ul>
{comments.map(comment => (
<li key={comment.id}>{comment.text}</li>
))}
</ul>
</section>
);
這樣就能自動渲染出所有留言,資料一改,畫面也會跟著更新,非常適合「資料驅動 UI」的開發方式。
❌ 常見錯誤 1:忘記加 key
// ⛔ 錯誤:沒有加 key
{items.map(item => <li>{item}</li>)}這會導致 React 顯示錯誤警告,也可能在重新渲染時出錯。
✅ 解法:永遠記得加上唯一的 key!
❌ 常見錯誤 2:直接插入陣列而不是元素
const names = ['Alice', 'Bob', 'Charlie'];
return <div>{names}</div>; // ⛔ 螢幕會顯示:Alice,Bob,Charlie(不會有標籤)
這樣只是把陣列當成字串輸出,並不是你想要的「一個一個包成 HTML 元素」。
✅ 正確方式:
{names.map((name, i) => <p key={i}>{name}</p>)}延伸技巧:清單項目可以是任何 JSX 元素
你不只可以產生 <li>,還可以是任意的 HTML 結構或自訂元件:
const products = [
{ id: 101, name: '蘋果', price: 30 },
{ id: 102, name: '香蕉', price: 20 },
];
return (
<div className="product-list">
{products.map(product => (
<div key={product.id} className="product-item">
<h3>{product.name}</h3>
<p>價格:${product.price}</p>
</div>
))}
</div>
);
這樣你就能根據資料清單產生整個畫面結構,甚至能封裝成子元件去管理每一項。
注意事項
在使用 JSX 時,雖然它的語法看起來很像 HTML,但實際上它是 JavaScript 的語法延伸,因此有一些「看起來像可以做,但實際上會報錯」的情況,特別需要注意。
第一點:不能在 JSX 中直接使用語句(statement)
JSX 中的 {} 是用來插入 JavaScript「表達式(expression)」的,而不是「語句(statement)」。
🔍 什麼是表達式(expression)?
- 表達式是會產生「值」的程式碼
- 例如:變數、運算、函式呼叫、三元運算子(
? :)
const name = '小明';
const greeting = `你好,${name}`; // ✅ 表達式❌ 錯誤:語句不能放進 JSX 的大括號中
以下範例會報錯,因為 if 是「語句」:
return (
<div>
{if (isOk) { return <p>OK</p>; }}
</div>
);
這樣會出現語法錯誤,因為 JSX 不接受 {} 中寫控制流程語法(if、for、while、switch 都不行)。
✅ 正確寫法:改用表達式(像是三元運算子)
你可以使用三元運算子(條件 ? 為真 : 為假)來達成同樣效果:
return (
<div>
{isOk ? <p>OK</p> : <p>Not OK</p>}
</div>
);
這樣寫是合法的,因為 isOk ? ... : ... 是一個完整會回傳值的表達式,可用於 JSX。
✅ 進階方式:將邏輯抽出到函式或外部變數中
如果條件邏輯很複雜,建議不要直接塞在 JSX 裡面,可以這樣寫:
let content;
if (isOk) {
content = <p>OK</p>;
} else {
content = <p>Not OK</p>;
}
return <div>{content}</div>;
這樣邏輯與畫面就分開來,程式會更清楚、好維護。
第二點:JSX 與 HTML 的細微差異
雖然 JSX 看起來像 HTML,但其實底層是 JavaScript,因此在語法上會有幾個地方不同,初學者要特別小心。
1. 屬性中插入變數,需要用 {}
在 HTML 中我們寫:
<h1 title="歡迎頁面">Hello</h1>
但在 JSX 中,如果你要插入一個變數當作屬性值,必須這樣寫:
const title = '歡迎頁面';
return <h1 title={title}>Hello</h1>;
因為 JSX 是 JavaScript,這裡的 title={title} 表示把變數 title 的值作為屬性值傳入。
2. class 屬性要寫成 className
因為 class 是 JavaScript 的保留字,JSX 使用 className 來取代 HTML 的 class:
return <div className="box">內容</div>;3. 有些屬性名稱也會不同
| HTML 屬性 | JSX 對應寫法 |
|---|---|
for | htmlFor |
class | className |
tabindex | tabIndex |
maxlength | maxLength |
結語:善用 {},讓你的 JSX 更靈活
學會在 JSX 中正確插入 JavaScript,是寫出靈活互動畫面的第一步。
記住,只能放「表達式」進 {},但你可以利用它做很多事情:顯示變數、呼叫函式、做條件判斷、顯示清單……熟悉這些用法後,你會發現 JSX 雖然看起來像 HTML,但其實比 HTML 更強大!