JSX 中如何插入 JavaScript?使用 {} 的基本原則
更新日期: 2025 年 3 月 30 日
本文為 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 更強大!