在前幾篇介紹表單的文章中,有說到表單的基本操作以及如何將資料送到後端
但是問題來了:誰來掌握表單輸入的資料?
舉個更貼近實際的例子:
我們需要登入一個帳戶,使用者需要輸入帳號密碼,但 React 要怎麼得知使用者輸入的值:
state
記錄第一種方式就是受控表單 (Controlled),第二種方式則是非受控表單 (Uncontrolled)
兩者主要的差別就在於:輸入值是由 React 控制,還是由 DOM 控制
React 強調「UI = State」,也就是畫面應該由 state
決定,而不是直接讓 DOM 管理值。
受控表單正是依循這個理念:
value
綁定 state
:輸入顯示的值直接來自 React state
onChange
更新 state
:每次使用者輸入時,React 都更新 state
state
掌控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>
);
}
ref
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
的功能:
<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>
);
}
瀏覽器執行畫面
受控 (Controlled) | 非受控 (Uncontrolled) | |
---|---|---|
資料來源 | React state | DOM |
操作方式 | value + onChange |
ref |
適合情境 | 需要驗證、即時反應、動態顯示 | 表單簡單、不需要驗證 |
優點 | 容易整合驗證邏輯、單一資料流 | 程式碼簡單 |
缺點 | 需要大量 state、程式碼較冗長 | 難以追蹤輸入變化 |
從上表可以看到,受控表單適合需要即時驗證或動態顯示的複雜情境,非受控表單則適合簡單情境或只在送出時取得值。