Skip to main content

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,必須在元件的最上層(不能在迴圈、條件或巢狀函數內使用)。

運作原理

  1. 第一次渲染時,useState(initialValue) 會將 state 設為 initialValue。

  2. 當您呼叫 setState(newValue),React 會:

    • 更新 state 為 newValue。

    • 觸發元件重新渲染,畫面會反映新的 state 值。

  3. 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;

如何運行這個範例

  1. 建立 React 專案(如果還沒有):

    • 在終端機運行以下指令,建立一個新的 React 專案:

      npx create-react-app counter-demo
      cd counter-demo
  2. 替換程式碼

    • 開啟 src 資料夾中的 App.js,將以下程式碼貼入:

      import React from "react";
      import Counter from "./Counter";

      function App() {
      return (
      <div>
      <Counter />
      </div>
      );
      }

      export default App;
    • 在 src 資料夾中新建一個檔案 Counter.js,將上面的計數器程式碼貼入。

  3. 啟動專案

    • 在終端機運行:

      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 同步。

如何運行

  1. 在您的 React 專案中,將上述程式碼存為 Form.js。

  2. 在 App.js 中匯入並使用:

    import React from "react";
    import Form from "./Form";

    function App() {
    return (
    <div>
    <Form />
    </div>
    );
    }

    export default App;
  3. 運行 npm start,您會看到一個輸入框,輸入內容後點擊提交會顯示警示框。


總結

  • state 是 React 中管理動態資料的核心,當 state 改變時,畫面會自動更新。

  • useState 是函數式元件的狀態管理工具,提供 state 和更新函數。

  • 透過計數器和表單範例,您可以看到 state 的實際應用。

  • 記得 state 是不可變的,使用 setState 更新,並注意非同步特性。