iT邦幫忙

2025 iThome 鐵人賽

DAY 24
0
Modern Web

30天入門:學會第一個前端框架-React系列 第 24

Day 24 | React入門:受控表單 VS. 非受控表單

  • 分享至 

  • xImage
  •  

在前幾篇介紹表單的文章中,有說到表單的基本操作以及如何將資料送到後端

但是問題來了:誰來掌握表單輸入的資料?

舉個更貼近實際的例子:
我們需要登入一個帳戶,使用者需要輸入帳號密碼,但 React 要怎麼得知使用者輸入的值:

  1. 每次輸入都回報給 React → React 用 state 記錄
  2. 讓瀏覽器自己管理 → 送出時再取值

第一種方式就是受控表單 (Controlled),第二種方式則是非受控表單 (Uncontrolled)
兩者主要的差別就在於:輸入值是由 React 控制,還是由 DOM 控制


受控表單的理念

React 強調「UI = State」,也就是畫面應該由 state 決定,而不是直接讓 DOM 管理值。
受控表單正是依循這個理念:

  • value 綁定 state:輸入顯示的值直接來自 React state
  • onChange 更新 state:每次使用者輸入時,React 都更新 state
  • 單向控制:表單輸入值完全由 React state 掌控

受控表單 ( Controlled Components ):

  • 定義:表單輸入的值由 React 的 state 控制,使用 value + onChange
  • 特點:每次輸入都會觸發 state 更新 ,且輸入值或跟著同步

範例:

import { useState } from "react";

export default function Contact() {
  const [email, setEmail] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    alert("受控送出的電子郵件:" + email);
  };

  return (
    <div style={{ border: "1px solid #ddd", padding: "1rem", borderRadius: "8px" }}>
      <h3>受控表單 (Controlled)</h3>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={email}
          placeholder="輸入電子郵件"
          onChange={(e) => setEmail(e.target.value)}
        />
        <button type="submit">送出</button>
      </form>
    </div>
  );
}

非受控表單 ( Uncontrolled Components ):

  • 定義:表單輸入的值交給 DOM 自己管理,要取得值時要使用 ref
  • 特點:React 不會即時追蹤值

範例:

import { useRef } from "react";

export default function Contact() {
  const emailRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    alert("非受控送出的電子郵件:" + emailRef.current.value);
  };

  return (
    <div>
      <h3>非受控表單 (Uncontrolled)</h3>
      <form onSubmit={handleSubmit}>
        <input type="text" ref={emailRef} placeholder="輸入電子郵件" />
        <button type="submit">送出</button>
      </form>
    </div>
  );
}

註:useRef 的功能:

  • 存取 DOM 元素:可以取得 <input><textarea> 等元素,讀取或操作它們的值
  • 儲存資料(不會觸發重新渲染):useRef.current 屬性可以存放任何值(例如數字、物件、函式...)

受控表單即時反應範例(字數統計),非受控表單無法做到

import { useState } from "react";

export default function Contact() {
  const [message, setMessage] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    alert("送出的訊息:" + message);
  };

  return (
    <form onSubmit={handleSubmit}>
      <textarea
        value={message}
        onChange={(e) => setMessage(e.target.value)}
        placeholder="輸入訊息"
      />
      <p style={{ fontSize: "0.9rem", color: "#555" }}>
        已輸入字數:{message.length}
      </p>
      <button type="submit">送出</button>
    </form>
  );
}

瀏覽器執行畫面
https://i.meee.com.tw/VkniTMM.gif


比較

受控 (Controlled) 非受控 (Uncontrolled)
資料來源 React state DOM
操作方式 value + onChange ref
適合情境 需要驗證、即時反應、動態顯示 表單簡單、不需要驗證
優點 容易整合驗證邏輯、單一資料流 程式碼簡單
缺點 需要大量 state、程式碼較冗長 難以追蹤輸入變化

從上表可以看到,受控表單適合需要即時驗證或動態顯示的複雜情境,非受控表單則適合簡單情境或只在送出時取得值。


如何選擇

  • 使用受控表單
    • 需要即時驗證(例如 email 格式檢查的即時提示)
    • 表單值會影響其他元件(例如字數限制的動態顯示)
  • 使用非受控表單
    • 只需要最後送出時讀取輸入值
    • 無須即時驗證的小表單

上一篇
Day 23 | React入門:React 中驗證表單
下一篇
Day 25 | React入門:表單送出後自動跳轉頁面-useNevigate
系列文
30天入門:學會第一個前端框架-React29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言