元件之間如何傳資料?Props 教學入門

更新日期: 2025 年 4 月 14 日

在使用 React 建構畫面時,你可能會遇到這樣的情境:「我有一個資料放在某個元件 A 裡,但我想讓元件 B 也可以用到這筆資料。」

這時候,你會開始思考「元件之間要怎麼傳資料?」這正是 propsproperties 的簡寫)登場的時候。

在 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} 來插入這筆資料,顯示在畫面上。

小結:整個資料流動過程

  1. 父元件內部宣告一個變數 user,值是 "小美"
  2. 父元件使用 <Child name={user} />,將資料以 props 傳給子元件
  3. 子元件透過 function Child({ name }) 解構取得資料
  4. 子元件將這筆資料渲染到畫面上

最終畫面會顯示:

嗨,我是小美

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} />
  • 你可以傳入 truefalse
  • 通常用於控制元件狀態(開/關、顯示/隱藏等)。
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 會:

  1. 讀到你插入了一個陣列
  2. 陣列中每個元素都是 React Element(JSX 標籤)
  3. React 會逐一渲染出這些元素
  4. 最後整個 <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:讓元件擁有「自己的記憶」,不只是顯示資料,更能根據使用者互動變化畫面,敬請期待!

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *