元件之間如何傳資料?Props 教學入門
更新日期: 2025 年 4 月 14 日
《React 元件基礎介紹》:
- React 的開發邏輯:為什麼現代前端要用元件?
- React 元件是什麼?畫面積木的基本單位
- 什麼是元件樹?理解元件的父子與巢狀結構
- 撰寫第一個 React 元件:函式型元件入門
- 如何規劃與拆分元件?從 UI 切割建立模組思維
- 元件之間如何傳資料?Props 教學入門
- 初學者也能懂!React children 全解析與實戰教學
- React 元件可以有自己的資料?state 基礎觀念與使用
- 什麼是 prop drilling?當資料傳遞變成麻煩
- Context API 是什麼?解決 prop drilling 的痛點
- 比 Context 更好用的選擇?認識第三方狀態管理工具
在閱讀本文前,建議先閱讀《JSX 基礎介紹》
在使用 React 建構畫面時,你可能會遇到這樣的情境:「我有一個資料放在某個元件 A 裡,但我想讓元件 B 也可以用到這筆資料。」
這時候,你會開始思考「元件之間要怎麼傳資料?」這正是 props
(properties 的簡寫)登場的時候。
在 React 中,props
是讓資料從父元件流向子元件的主要方式。
如果你想建立一個有互動性的 UI,學會 props 是第一步。
什麼是 props?
props 就是元件的「參數」
在 React 中,元件(Component)其實本質上就是一種「函式」,而這個函式可以接收一些「外部傳進來的值」來決定它要如何顯示畫面。
這些值,就稱為 props,是 properties(屬性) 的縮寫。
你可以把 React 的元件想像成「接收資料 → 輸出畫面」的工廠,這些傳進來的資料(也就是 props)會被元件用來組合出對應的畫面內容。
實際範例來看:
先定義一個元件 Welcome
,它會使用 props 來顯示歡迎文字:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
這裡的 props
是一個 JavaScript 物件,裡面會包含所有從父元件傳進來的資料。
在這個例子中,我們只使用了 props.name
,代表我們想從外部取得一個名字來顯示。
當你在 JSX 中寫下這樣的語法:
<Welcome name="小明" />
React 在背後會自動把這整個元件的「屬性(attributes)」整理成一個 JavaScript 物件,也就是:
{
name: "小明"
}
然後把這個物件當作參數,傳給 Welcome
元件這個函式使用。所以這背後等同於這樣的呼叫:
Welcome({ name: "小明" });
這就是為什麼我們在 Welcome
裡面會寫成:
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
這裡的 props
就是那個物件 { name: "小明" }
。
🖥️ 最終畫面結果:
Hello, 小明!
props.name
的值是 "小明"
,因此會被插入到 JSX 中,並渲染成一段包含個人名字的歡迎語句。
延伸:如果傳更多 props 會怎樣?
假設你這樣用:
<Welcome name="小明" age={18} isStudent={true} />
React 背後做的事情會是:
Welcome({
name: "小明",
age: 18,
isStudent: true
});
你在元件裡就可以這樣讀取它們:
function Welcome(props) {
return (
<div>
<p>姓名:{props.name}</p>
<p>年齡:{props.age}</p>
<p>{props.isStudent ? "是學生" : "不是學生"}</p>
</div>
);
}
這樣一來,元件就可以根據不同資料呈現不同內容,超級有彈性 🙌
如果你之後想用「解構賦值」的寫法,讓程式碼更清楚一點,也可以這樣寫:
function Welcome({ name, age, isStudent }) {
return (
<div>
<p>姓名:{name}</p>
<p>年齡:{age}</p>
<p>{isStudent ? "是學生" : "不是學生"}</p>
</div>
);
}
這種寫法很常見,也更直觀!
為什麼這個概念重要?
因為在 React 中,我們會大量使用元件來組裝畫面,而畫面內容常常會根據資料不同而變化。
如果沒有 props,元件就只能寫死資料(hardcoded),那就完全失去彈性了。
使用 props,我們就能:
- 建立可重用的元件
- 根據不同的資料動態變化畫面
- 建立清楚的資料傳遞路徑(由父元件向子元件)
父子元件之間傳資料的範例
React 的元件就像拼圖一樣,每個元件都專注在自己的任務上,而透過 props
,這些拼圖可以分享資料、協同合作。
來看一個簡單的實例,我們要讓一個父元件(Parent
)把一筆使用者名稱資料,傳給子元件(Child
)來顯示。
父元件
function Parent() {
const user = "小美"; // 宣告一個變數
return <Child name={user} />; // 把 user 傳進子元件
}
這裡的關鍵是 <Child name={user} />
:
Child
是我們要使用的子元件name={user}
就是設定一個名為name
的 props,把變數user
的值(”小美”)傳給子元件
你可以把它想像成是呼叫函式時傳入的參數:
Child({ name: "小美" });
JSX 插入變數方法:{ 變數 }
📌 拆解說明
在 HTML 中,我們會這樣寫屬性:
<img src="photo.jpg" />
在 JSX 中也可以類似這樣寫,但當屬性的值是 JavaScript 表達式(例如變數、函式、數字等),就要使用大括號 {}
包起來:
<Child name={"小美"} /> // 字串
<Child name={user} /> // 傳變數
<Child count={1 + 2} /> // 傳運算結果
<Child onClick={handleClick} /> // 傳函式
🧠 JSX 背後的本質:轉成 JavaScript 呼叫
這段 JSX:
<Child name={user} />
在 React 背後會被轉換成這樣的 JavaScript:
React.createElement(Child, { name: user });
所以其實 name={user}
就是把一個 name
屬性放進 props 物件裡!
好問題!這裡其實牽涉到 JSX 的語法規則,讓我幫你完整解析一下:
如果你這樣寫:
<Child name=user />
React(或其背後的轉譯工具 Babel)會報錯,因為這違反了 JSX 的語法規定。
✋ 為什麼會錯?
因為 JSX 的屬性值若要插入 JavaScript 表達式(變數、函式、邏輯運算、計算式等等),必須使用大括號 {}
包起來。
// 正確 ✅
<Child name={user} />
// 錯誤 ❌
<Child name=user />
你這樣寫會被 JSX 當作字串解析的錯誤嘗試,但它又不是合法的 HTML 字串語法,React 就會報錯。
🔎 React 是怎麼理解你的寫法的?
在 HTML 中,這樣的寫法:
<img src=photo.jpg />
等價於:
<img src="photo.jpg" />
HTML 允許屬性值可以不加引號(在某些情況下)。
但 JSX 不一樣,它是 JavaScript 世界的語法,它要求更明確的語意:
- 若是字串:你可以用雙引號,例如
name="小美"
- 若是JavaScript 表達式(變數、邏輯、函式):你要用大括號
{}
包起來,例如name={user}
✅ 正確語法對照表
想傳什麼 | 正確寫法 | 說明 |
---|---|---|
字串 "小美" | <Child name="小美" /> | JSX 會當成字串 |
變數 user | <Child name={user} /> | 使用大括號表示這是 JS 變數 |
數字 123 | <Child age={123} /> | 數字也是 JS 表達式 |
函式 handleClick | <Child onClick={handleClick} /> | 傳入函式作為 props |
子元件
function Child({ name }) {
return <p>嗨,我是{name}</p>;
}
在 Child
元件裡,我們使用了解構賦值(Destructuring)語法,直接從 props
中取出 name
。然後使用 {name}
來插入這筆資料,顯示在畫面上。
小結:整個資料流動過程
- 父元件內部宣告一個變數
user
,值是"小美"
- 父元件使用
<Child name={user} />
,將資料以props
傳給子元件 - 子元件透過
function Child({ name })
解構取得資料 - 子元件將這筆資料渲染到畫面上
最終畫面會顯示:
嗨,我是小美
props 是單向資料流:只能從父傳子
React 的資料傳遞採用 單向資料流(One-way Data Flow),也就是說:
❗ 資料只能從「父元件 → 子元件」流動,不能反過來!
這個設計不是限制,而是一種 資料管理的策略。
當資料只能單向流動時,開發者就能更容易掌握資料的變化、追蹤 bug,也不容易讓資料混亂、難以除錯。
錯誤示範:子元件嘗試修改 props
function Child({ count }) {
count++; // ❌ 錯誤!直接修改 props 是禁止的
return <p>{count}</p>;
}
這段程式碼看起來沒什麼問題,但在 React 裡,props 是唯讀的(read-only),不應該、也不能直接修改。
如果你想讓子元件影響資料,正確的做法應該是:由父元件定義狀態(state),並把更新狀態的函式也一起傳進子元件。
這樣子元件就能「通知」父元件該更新資料,而不是自己動手改 props。
正確觀念:子元件傳事件回父元件處理
這樣的設計模式會長這樣(概念先略懂,之後的章節會深入):
function Parent() {
const [count, setCount] = useState(0);
return <Child count={count} onAdd={() => setCount(count + 1)} />;
}
function Child({ count, onAdd }) {
return (
<div>
<p>{count}</p>
<button onClick={onAdd}>+1</button>
</div>
);
}
這種寫法就是讓:
- 資料還是掌控在父元件手上
- 子元件只是觸發事件,讓父元件決定是否要更新資料
這符合 React 的設計哲學:「資料單向流動、元件高內聚、狀態集中管理」
props 可以傳遞哪些型別?
在 React 中,props
就像是元件的參數,因此你可以把任何 JavaScript 中的合法資料型別,當作 props 傳進元件裡。
重點不在於你「能不能傳」,而在於子元件「是否知道如何使用它」。以下是常見的幾種 props 資料型別,搭配對應範例說明:
字串(String)
<Message text="Hello" />
- JSX 中直接使用雙引號
"
包住字串。 - 在子元件中可以透過
props.text
取得"Hello"
。
function Message({ text }) {
return <p>{text}</p>;
}
數字(Number)
<Price value={100} />
- 使用
{}
將數字當作 JavaScript 表達式傳入。 - 常見於價格、計數器、評分等需求。
function Price({ value }) {
return <p>價格:${value}</p>;
}
布林值(Boolean)
<Toggle isActive={true} />
- 你可以傳入
true
或false
。 - 通常用於控制元件狀態(開/關、顯示/隱藏等)。
function Toggle({ isActive }) {
return <p>{isActive ? "啟用中" : "已關閉"}</p>;
}
📌 小提醒:如果只寫 isActive
,React 會視為 true
:
<Toggle isActive /> // 等同於 <Toggle isActive={true} />
陣列或物件(Array / Object)
<List items={[1, 2, 3]} />
<UserInfo data={{ name: "小美", age: 20 }} />
- 很常見於需要傳多筆資料或複雜結構的元件。
- 在子元件中要注意資料的結構,通常會搭配
.map()
或解構使用。
function List({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
🧩 React 為什麼可以在 JSX 中插入陣列?
在學習 React 的過程中,你可能會看到這樣的程式碼:
function List({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
假設你傳入的 items
是這樣的陣列:
const items = ['蘋果', '香蕉', '芒果'];
那這段 items.map(...)
實際上會回傳這樣的內容:
[
<li key={0}>蘋果</li>,
<li key={1}>香蕉</li>,
<li key={2}>芒果</li>
]
所以這段:
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
相當於:
<ul>
<li key={0}>蘋果</li>
<li key={1}>香蕉</li>
<li key={2}>芒果</li>
</ul>
這是一個由 React Elements(也就是 JSX 標籤)組成的陣列。React 會自動把這個陣列中的元素,一個一個渲染到 <ul>
元素中,最後畫面會呈現出一整排 <li>
清單。
✅ 為什麼這段寫法是合法的?
這段看起來有點神奇,但其實它背後建立在三個核心概念上:
🔹 1. JSX 中的 {}
:可以插入任意 JavaScript 表達式
JSX 並不是 HTML,它是 JavaScript 的語法糖。
你可以在 JSX 標籤中用 {}
插入任何合法的 JavaScript 表達式,例如:
<p>{1 + 1}</p> // 顯示 2
<p>{'Hello'.toUpperCase()}</p> // 顯示 HELLO
<p>{getMessage()}</p> // 顯示函式回傳值
✅ 陣列也是合法的 JavaScript 表達式。
🔹 2. React 支援陣列型 children
:可以插入一整個元素陣列
你可以寫這樣的程式碼:
const list = [
<li key="1">蘋果</li>,
<li key="2">香蕉</li>,
<li key="3">芒果</li>,
];
return <ul>{list}</ul>;
React 會:
- 讀到你插入了一個陣列
- 陣列中每個元素都是 React Element(JSX 標籤)
- React 會逐一渲染出這些元素
- 最後整個
<ul>
裡就會出現三個<li>
✅ 這個設計讓你可以用 .map()
輕鬆建立動態清單。
🔹 3. JSX 實際會被轉換為 JavaScript 函式呼叫
這段 JSX:
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
會被 Babel 轉譯成 JavaScript 函式呼叫:
React.createElement(
'ul',
null,
items.map((item, index) =>
React.createElement('li', { key: index }, item)
)
);
React 看到 children 是一個陣列,就會展開它、渲染其中的每一個項目。
✨ 清單渲染的標準寫法
實務上,我們通常會搭配 .map()
來產出 React Element 陣列,例如:
const fruits = ['蘋果', '香蕉', '芒果'];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={index}>{fruit}</li>
))}
</ul>
);
這是 React 處理重複資料最自然的寫法,也是你在大多數 React 專案中會看到的模式。
📌 關於 key
:每個項目都應有唯一識別
當你用 .map()
建立清單時,React 要求你提供一個 key
:
<li key={index}>{fruit}</li>
這個 key
:
- 不會出現在畫面上
- 但對 React 來說非常重要
- 幫助它在 DOM 更新時追蹤哪些項目是新增、刪除、或只是變更內容
✅ 實務建議:如果有唯一識別 ID(如資料庫主鍵),用那個;沒有的話,才用 index
。
🚫 常見錯誤:只放字串陣列,沒包成元素
<ul>{['蘋果', '香蕉', '芒果']}</ul>
這段語法上沒錯,但畫面會變成:
<ul>
蘋果香蕉芒果
</ul>
原因是:字串不是 React Element,所以它會被當成文字節點插進去,而不是 <li>
。
✅ 解法:務必用 JSX 包起來!
<ul>
{['蘋果', '香蕉', '芒果'].map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
🧠 小總結:React 為什麼能這樣做?
概念 | 說明 |
---|---|
JSX 支援 {} | 可以插入任何 JS 表達式 |
陣列是表達式 | [1, 2, 3] 是合法值 |
React 可展開 children 陣列 | 陣列中的 JSX 會被逐一渲染 |
key 是清單渲染必備 | 幫助 React 正確追蹤元素變化 |
✅ 實務結論:清單渲染是 React 最常見的應用模式之一
React 被設計成資料驅動的 UI 框架,你會不斷地處理「一批資料」變成「一組畫面元素」的情境。
而 .map()
+ 陣列渲染,就是這個需求最典型的解法。
如果你理解了:
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
你就掌握了 React 的核心用法之一。
函式(Function / Callback)
<Button onClick={handleClick} />
- 你可以把函式當作 props 傳入,讓子元件「通知父元件」某件事發生了(例如按鈕被點擊)。
- 這是實現元件之間互動的關鍵技巧。
function Button({ onClick }) {
return <button onClick={onClick}>點我</button>;
}
JSX / React 元件
<Card content={<UserInfo />} />
- 你甚至可以把 整個元件、JSX 標籤、或 React 元素 當作 props 傳進去。
- 通常會搭配
children
或像content
這樣的自定義欄位來渲染。
function Card({ content }) {
return (
<div className="card">
{content}
</div>
);
}
或用標準的 children
props:
<Card>
<UserInfo />
</Card>
function Card({ children }) {
return <div className="card">{children}</div>;
}
這種寫法讓元件可以更靈活地「嵌套」其他內容。
小結:你可以傳進來的類型有哪些?
資料型別 | 範例 | 用途說明 |
---|---|---|
字串 | "Hello" | 顯示文字、標題等 |
數字 | {100} | 價格、數量、評分等 |
布林 | {true} / {false} | 控制顯示狀態 |
陣列 | {[1, 2, 3]} | 清單渲染 |
物件 | {{ name: "小美" }} | 傳多個欄位資料 |
函式 | {handleClick} | 事件處理、狀態改變 |
JSX 元素 | {<UserInfo />} | 傳子元件畫面、動態嵌套 |
🎯 關鍵觀念
React 的
props
沒有限制你只能傳什麼型別,因為它本質就是一個 JavaScript 物件,你想傳什麼都行。但重點是:子元件要能正確理解與使用你傳進來的值。
結語:props 是元件之間溝通的第一步
在 React 世界裡,畫面是由一個個小元件組合而成,而 props
正是讓這些元件彼此「對話」的語言。
掌握 props 的用法,你就已經踏出組建動態 UI 的第一步!
下一篇,我們將介紹 state:讓元件擁有「自己的記憶」,不只是顯示資料,更能根據使用者互動變化畫面,敬請期待!