React 組件狀態
## React 組件狀態(State)是什麼?
狀態是組件內部會隨使用者操作而改變的資料,例如:
- 計數器目前的數字
- 輸入框的文字
- 選單是否開啟
- 使用者是否登入
當狀態改變時,React 會重新執行組件函式並重新渲染畫面。
### State 與 Props 的差異
| 項目 | State | Props |
|---|---|---|
| 來源 | 組件自己管理 | 父組件傳入 |
| 是否可直接修改 | 不可以直接修改 | 不可以直接修改 |
| 用途 | 管理組件內部會變化的資料 | 傳遞資料或事件給子組件 |
---
## `useState` 基本語法
```jsx
import { useState } from "react";
function Example() {
const [state, setState] = useState(initialValue);
return (
// JSX
);
}
```
例如:
```jsx
const [count, setCount] = useState(0);
```
這行程式碼會產生:
- `count`:目前的狀態值
- `setCount`:更新狀態的函式
- `0`:初始值
更新狀態:
```jsx
setCount(10);
```
如果新的狀態依賴舊狀態,建議使用函式形式:
```jsx
setCount(previousCount => previousCount + 1);
```
不要直接修改狀態:
```jsx
// 不建議
count = count + 1;
```
而應該透過 setter:
```jsx
setCount(count + 1);
```
---
# 範例一:計數器
這個範例展示如何使用狀態儲存數字,並透過按鈕更新它。
```jsx
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
function increase() {
setCount(previousCount => previousCount + 1);
}
function decrease() {
setCount(previousCount => previousCount - 1);
}
return (
<div>
<h2>目前數字:{count}</h2>
<button onClick={increase}>增加</button>
<button onClick={decrease}>減少</button>
<button onClick={() => setCount(0)}>歸零</button>
</div>
);
}
export default Counter;
```
### 運作流程
1. `useState(0)` 將 `count` 初始值設為 `0`
2. 使用者點擊「增加」
3. 呼叫 `setCount`
4. React 更新 `count`
5. 組件重新渲染,畫面顯示新的數字
---
# 範例二:輸入框與顯示文字
這個範例展示如何讓狀態跟表單輸入同步。
```jsx
import { useState } from "react";
function NameInput() {
const [name, setName] = useState("");
return (
<div>
<label>
請輸入姓名:
<input
value={name}
onChange={event => setName(event.target.value)}
/>
</label>
<p>
你好,{name || "訪客"}!
</p>
</div>
);
}
export default NameInput;
```
### 運作流程
1. `name` 初始值是空字串
2. 使用者在輸入框輸入文字
3. `onChange` 事件被觸發
4. `setName(event.target.value)` 更新狀態
5. React 重新渲染,`<p>` 顯示最新文字
這種寫法稱為「受控元件」:輸入框的內容由 React 的 state 控制。
---
## 重要注意事項
### 1. 狀態更新可能會被批次處理
如果連續更新狀態,建議使用前一個狀態的函式:
```jsx
setCount(count + 1);
setCount(count + 1);
```
這不一定會增加兩次,因為兩次可能都使用相同的舊值。
應改成:
```jsx
setCount(previousCount => previousCount + 1);
setCount(previousCount => previousCount + 1);
```
### 2. 陣列與物件不要直接修改
不建議:
```jsx
user.name = "小明";
```
應建立新的物件:
```jsx
setUser({
...user,
name: "小明"
});
```
陣列也一樣:
```jsx
setItems([...items, newItem]);
```
React 依靠新的參照判斷狀態是否改變,因此應使用新的陣列或物件來更新狀態。
相關學習地圖、教學課程
F2E 網站前端工程