測驗:Props 與 State:資料流的核心概念
共 5 題,點選答案後會立即顯示結果
1. 關於 Props 的特性,下列哪個敘述是正確的?
2. 以下程式碼中,useState(0) 的 0 代表什麼?
3. 為什麼更新 State 時需要建立新的值,而不是直接修改原本的值?
4. 在「受控元件」模式中,表單輸入框的值是由什麼控制的?
5. 下列哪種情況應該使用 State 而非 Props?
前言
在上一篇文章中,我們學會了用 JSX 建立元件。但你可能會發現,那些元件都是「靜態」的——每次渲染都顯示一樣的內容。
當你用 AI 生成的 React 程式碼越來越複雜,你會開始看到兩個關鍵字不斷出現:Props 和 State。這兩個概念是 React 資料流的核心,理解它們,你就能看懂大部分 React 程式碼的運作邏輯。
Props:從父元件傳來的資料
Props 是什麼?
Props(Properties 的縮寫)是父元件傳遞給子元件的資料。你可以把它想像成函式的參數。
// 父元件傳遞資料
<Greeting name="小明" />
// 子元件接收資料
function Greeting(props) {
return <h1>你好,{props.name}!</h1>;
}
Code language: JavaScript (javascript)當你在 AI 生成的程式碼中看到元件標籤上有 key="value" 的寫法,那就是在傳遞 Props。
解構賦值:更常見的寫法
實務上,你更常看到這種寫法:
function Greeting({ name }) {
return <h1>你好,{name}!</h1>;
}
Code language: JavaScript (javascript)這是 JavaScript 的「解構賦值」語法,直接從 props 物件中取出需要的屬性。當 Props 很多時,這種寫法特別清楚:
function UserCard({ name, email, avatar, isOnline }) {
return (
<div className="user-card">
<img src={avatar} alt={name} />
<h2>{name}</h2>
<p>{email}</p>
{isOnline && <span className="online-badge">線上</span>}
</div>
);
}
Code language: JavaScript (javascript)Props 的重要特性:唯讀
Props 是唯讀的,子元件不能修改收到的 Props。這是 React 的設計原則——資料只能從父元件流向子元件,這種「單向資料流」讓程式更容易理解和除錯。
// 錯誤示範 - 不要這樣做!
function Greeting({ name }) {
name = "小華"; // React 會報錯或行為異常
return <h1>你好,{name}!</h1>;
}
Code language: JavaScript (javascript)State:元件內部的可變資料
為什麼需要 State?
Props 是從外部傳入的,但有時候元件需要自己管理一些會變動的資料,例如:
- 使用者輸入的內容
- 按鈕的點擊次數
- 選單是否展開
這就是 State 的用途。
useState Hook 基本用法
React 提供 useState 這個 Hook 來管理狀態:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>目前計數:{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Code language: JavaScript (javascript)讓我們拆解這段程式碼:
const [count, setCount] = useState(0);
// ↑ ↑ ↑
// 狀態值 更新函式 初始值
Code language: JavaScript (javascript)count:目前的狀態值setCount:用來更新狀態的函式useState(0):設定初始值為 0
狀態更新的不可變性原則
這是新手最容易踩的坑。更新狀態時,你必須建立新的值,而不是直接修改原本的值。
// 基本型別:直接設定新值即可
const [count, setCount] = useState(0);
setCount(count + 1); // 正確
// 陣列:使用展開運算子建立新陣列
const [items, setItems] = useState(['蘋果', '香蕉']);
setItems([...items, '橘子']); // 正確:建立新陣列
items.push('橘子'); // 錯誤:直接修改原陣列
// 物件:同樣使用展開運算子
const [user, setUser] = useState({ name: '小明', age: 20 });
setUser({ ...user, age: 21 }); // 正確:建立新物件
user.age = 21; // 錯誤:直接修改原物件
Code language: JavaScript (javascript)為什麼要這樣?因為 React 是透過比較「前後的值是否相同」來決定要不要重新渲染。如果你直接修改原本的物件,React 會認為「值沒變」而不更新畫面。
Props vs State:何時用哪個?
這是初學者最常問的問題。簡單的判斷原則:
| 情境 | 使用 |
|---|---|
| 資料從父元件傳來 | Props |
| 資料在元件內部產生並管理 | State |
| 資料不會改變 | Props |
| 資料會因使用者操作而改變 | State |
實際範例:待辦事項
function TodoApp() {
// State:在這個元件內管理的資料
const [todos, setTodos] = useState([
{ id: 1, text: '學習 React' },
{ id: 2, text: '寫程式' }
]);
const [inputValue, setInputValue] = useState('');
const addTodo = () => {
if (inputValue.trim()) {
setTodos([...todos, {
id: Date.now(),
text: inputValue
}]);
setInputValue('');
}
};
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="輸入待辦事項"
/>
<button onClick={addTodo}>新增</button>
{todos.map(todo => (
// Props:傳遞給子元件的資料
<TodoItem key={todo.id} text={todo.text} />
))}
</div>
);
}
function TodoItem({ text }) {
// 這個元件只負責顯示,text 是從 Props 來的
return <div className="todo-item">{text}</div>;
}
Code language: JavaScript (javascript)在這個例子中:
todos和inputValue是 State,因為它們會隨使用者操作改變text是 Props,因為它是從TodoApp傳給TodoItem的
表單輸入的處理模式
你會在 AI 生成的程式碼中經常看到這種模式:
function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log('登入資訊:', { email, password });
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="電子郵件"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="密碼"
/>
<button type="submit">登入</button>
</form>
);
}
Code language: JavaScript (javascript)這種模式叫做「受控元件」(Controlled Component):
value={email}:輸入框的值由 State 控制onChange={(e) => setEmail(e.target.value)}:每次輸入都更新 State
這樣 React 就能完全掌控表單的狀態。
Vibe Coding 技巧:請 AI 解釋資料流
當你看到複雜的 React 程式碼,不確定資料怎麼流動時,可以這樣問 AI:
「請解釋這段程式碼的資料流向。哪些是 Props?哪些是 State?資料是怎麼從父元件傳到子元件的?」
或者更具體地:
「這個
user變數是從哪裡來的?它是 Props 還是 State?在什麼時候會被更新?」
AI 會幫你追蹤資料的來源和流向,這比自己慢慢看要快得多。
常見錯誤與除錯
1. 直接修改 State
// 錯誤
const [items, setItems] = useState([1, 2, 3]);
items.push(4); // 畫面不會更新!
// 正確
setItems([...items, 4]);
Code language: JavaScript (javascript)2. 在條件式中使用 Hook
// 錯誤
function MyComponent({ showCount }) {
if (showCount) {
const [count, setCount] = useState(0); // Hook 不能放在條件式裡!
}
}
// 正確
function MyComponent({ showCount }) {
const [count, setCount] = useState(0);
if (!showCount) return null;
return <p>{count}</p>;
}
Code language: JavaScript (javascript)3. 忘記設定 key
// 會有警告
{todos.map(todo => (
<TodoItem text={todo.text} />
))}
// 正確
{todos.map(todo => (
<TodoItem key={todo.id} text={todo.text} />
))}
Code language: JavaScript (javascript)本篇重點回顧
- Props 是父元件傳給子元件的資料,唯讀不可修改
- State 是元件內部管理的可變資料,用
useState宣告 - 更新 State 時要建立新的值,不能直接修改原本的值
- 從父元件來的資料用 Props,元件自己管理的資料用 State
- 受控元件模式:用 State 控制表單輸入值
下一步
現在你理解了 React 的資料流核心概念。下一篇我們會學習如何用條件渲染和列表渲染,讓元件根據資料動態顯示不同的內容。
進階測驗:Props 與 State:資料流的核心概念
共 5 題,包含情境題與錯誤診斷題。