React 畫面更新的發動機:state 初探
什麼是 state
在 React 中,state 是用來管理元件內部資料的一種機制。當 state 的值改變時,React 會自動重新渲染(re-render)元件,讓畫面更新以反映最新的資料。簡單來說,state 就像是元件的「記憶」,讓元件能夠記錄和追蹤資料的變化,例如使用者的輸入、按鈕的點擊次數或表單的狀態等。
為什麼需要 state?
-
動態更新畫面:如果資料是靜態的(例如固定的文字),可以用普通的變數。但如果資料會隨著使用者互動而改變(例如計數器增加),就需要 state。
-
單向資料流:React 的資料流是單向的,state 改變會觸發畫面更新,確保畫面與資料一致。
-
元件內部管理:state 是元件私有的,僅在該元件內部使用,不會影響其他元件。
與普通變數的差別
如果直接用普通的 JavaScript 變數(例如 let count = 0)來儲存資料,改變這個變數不會觸發 React 重新渲染畫面。而 state 由 React 管理,當 state 更新時,React 會自動重新渲染元件,更新畫面。
useState 初探
在 React 的函數式元件中,useState 是一個內建的 Hook,用來宣告和管理 state。它讓函數式元件也能擁有狀態管理的能力,取代了過去類別元件中的 this.state。
useState 的基本語法
import React, { useState } from "react";
const [state, setState] = useState(initialValue);
-
state:這是您用來儲存資料的變數名稱,代表目前的狀態值。
-
setState:這是一個函數,用來更新 state 的值。當您呼叫 setState 時,React 會更新 state 並觸發元件重新渲染。
-
initialValue:state 的初始值,可以是數字、字串、物件、陣列等任何 JavaScript 值。
-
useState:從 react 模組匯入的 Hook,必須在元件的最上層(不能在迴圈、條件或巢狀函數內使用)。
運作原理
-
第一次渲染時,useState(initialValue) 會將 state 設為 initialValue。
-
當您呼叫 setState(newValue),React 會:
-
更新 state 為 newValue。
-
觸發元件重新渲染,畫面會反映新的 state 值。
-
-
state 是不可變的,您不能直接修改 state(例如 state = newValue),必須使用 setState。
useState 的範例演示
以下是一個簡單的計數器範例,展示如何使用 useState 來管理狀態並更新畫面。您可以跟著操作這個範例,逐步理解 useState 的用法。
範例:計數器元件
這個範例會建立一個計數器,包含「增加」、「減少」和「重置」按鈕,讓您看到 state 改變如何影響畫面。
完整程式碼
import React, { useState } from "react";
function Counter() {
// 宣告 state,初始值為 0
const [count, setCount] = useState(0);
// 增加計數的函數
const increment = () => {
setCount(count + 1);
};
// 減少計數的函數
const decrement = () => {
setCount(count - 1);
};
// 重置計數的函數
const reset = () => {
setCount(0);
};
return (
<div>
<h1>計數器: {count}</h1>
<button onClick={increment}>增加</button>
<button onClick={decrement}>減少</button>
<button onClick={reset}>重置</button>
</div>
);
}
export default Counter;
如何運行這個範例
-
建立 React 專案(如果還沒有):
-
在終端機運行以下指令,建立一個新的 React 專案:
npx create-react-app counter-demo
cd counter-demo
-
-
替換程式碼:
-
開啟 src 資料夾中的 App.js,將以下程式碼貼入:
import React from "react";
import Counter from "./Counter";
function App() {
return (
<div>
<Counter />
</div>
);
}
export default App; -
在 src 資料夾中新建一個檔案 Counter.js,將上面的計數器程式碼貼入。
-
-
啟動專案:
-
在終端機運行:
npm start
-
瀏覽器會自動開啟 http://localhost:3000 ,您會看到計數器介面。
-
程式碼解析
-
const [count, setCount] = useState(0);
:-
宣告一個 state 變數 count,初始值為 0。
-
setCount 是更新 count 的函數。
-
-
事件處理函數:
-
increment:呼叫
setCount(count + 1)
,將 count 增加 1。 -
decrement:呼叫
setCount(count - 1)
,將 count 減少 1。 -
reset:呼叫
setCount(0)
,將 count 重置為 0。
-
-
畫面渲染:
-
<h1>計數器: {count}</h1>
顯示目前的 count 值。 -
按鈕的 onClick 屬性綁定對應的事件處理函數,當按下按鈕時,setCount 會更新 state,React 會重新渲染畫面。
-
操作結果
-
點擊「增加」按鈕,計數器值加 1。
-
點擊「減少」按鈕,計數器值減 1。
-
點擊「重置」按鈕,計數器值回到 0。
-
每次 state 改變,畫面都會自動更新,顯示最新的 count 值。
關於 state 的補充觀念
以下是一些關於 state 的重要補充觀念,幫助您更深入理解並正確使用 useState。
1. state 是不可變的
您不能直接修改 state 的值,必須透過 setState 函數來更新。例如:
// 錯誤示範:直接修改 state
count = count + 1; // 這不會觸發畫面更新,且違反 React 規則
// 正確做法:使用 setCount
setCount(count + 1);
2. state 更新是非同步的
當您呼叫 setState 時,React 不會立即更新 state,而是將更新排程到下一次渲染。為了確保使用最新的 state 值,特別是在連續更新時,可以使用函數式更新:
// 連續增加計數
const incrementMultiple = () => {
setCount((prevCount) => prevCount + 1); // 使用前一個 state 值
setCount((prevCount) => prevCount + 1); // 再增加一次
};
- prevCount 是前一個 state 值,確保每次更新都基於最新的 state。
3. state 可以是任何資料型態
useState 的初始值可以是數字、字串、布林值、物件、陣列等。例如:
const [user, setUser] = useState({ name: "小明", age: 25 });
const [items, setItems] = useState(["蘋果", "香蕉"]);
4. 更新物件或陣列時要小心
由於 state 是不可變的,更新物件或陣列時,必須創建一個新的物件或陣列。例如:
// 更新物件
const updateUser = () => {
setUser({ ...user, age: user.age + 1 }); // 使用展開運算子複製並更新
};
// 更新陣列
const addItem = () => {
setItems([...items, "橘子"]); // 複製陣列並添加新項目
};
5. useState 的規則
-
只能在元件頂層使用:不能在迴圈、條件語句或巢狀函數內呼叫 useState。
-
每個 state 是獨立的:如果需要管理多個狀態,可以多次呼叫 useState:
const [count, setCount] = useState(0);
const [name, setName] = useState("");
6. 性能注意事項
-
如果 setState 傳入的值與當前 state 相同,React 會跳過重新渲染以提升性能。
-
過多的 state 或複雜的 state 更新可能影響效能,建議將相關狀態合併為單一物件。
進階範例:表單輸入
以下是一個更實際的範例,展示如何使用 useState 管理表單輸入,讓您進一步練習。
程式碼
import React, { useState } from "react";
function Form() {
const [name, setName] = useState("");
const handleChange = (event) => {
setName(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
alert(`您輸入的名字是:${name}`);
};
return (
<div>
<h1>簡單表單</h1>
<form onSubmit={handleSubmit}>
<label>
名字:
<input type="text" value={name} onChange={handleChange} />
</label>
<button type="submit">提交</button>
</form>
<p>目前輸入:{name}</p>
</div>
);
}
export default Form;
程式碼解析
-
const [name, setName] = useState('');:宣告一個 name state,初始值為空字串。
-
handleChange:當輸入框內容改變時,透過
[event.target](event.target).value
取得輸入值並更新 name。 -
handleSubmit:表單提交時,防止預設行為並顯示一個警示框,顯示輸入的名字。
-
受控元件:
<input>
的 value 綁定到 name state,onChange 綁定到 handleChange,確保輸入框與 state 同步。
如何運行
-
在您的 React 專案中,將上述程式碼存為 Form.js。
-
在 App.js 中匯入並使用:
import React from "react";
import Form from "./Form";
function App() {
return (
<div>
<Form />
</div>
);
}
export default App; -
運行 npm start,您會看到一個輸入框,輸入內容後點擊提交會顯示警示框。
總結
-
state 是 React 中管理動態資料的核心,當 state 改變時,畫面會自動更新。
-
useState 是函數式元件的狀態管理工具,提供 state 和更新函數。
-
透過計數器和表單範例,您可以看到 state 的實際應用。
-
記得 state 是不可變的,使用 setState 更新,並注意非同步特性。