在 React 中,?受控組件(Controlled Components)? 和 ?非受控組件(Uncontrolled Components)? 是處理表單元素的兩種不同方式,它們的核心區別在于 ?數據管理的方式 和 ?與 React 的交互模式。
受控組件(Controlled Components)
定義
表單元素(如 <input>
、<textarea>
、<select>
)的值由 ?React
的 state
完全控制。用戶輸入會觸發 React
的狀態更新,表單的當前值始終與 React
的 state
同步。
關鍵特征
- 數據流:單向綁定(從 React state 到 DOM)。
- 更新方式:通過 onChange 事件手動更新 state。
- 值的來源:組件的 value 或 checked 屬性直接綁定到 state。
代碼示例
import { useState } from 'react';function ControlledForm() {const [inputValue, setInputValue] = useState('');const handleChange = (e) => {setInputValue(e.target.value); // 手動同步到 state};return (<inputtype="text"value={inputValue} // 值由 React state 控制onChange={handleChange}/>);
}
適用場景
- 需要實時驗證輸入(如密碼強度檢查)。
- 動態表單(如根據輸入內容顯示其他字段)。
- 強制輸入格式(如只能輸入數字)。
優點
- 完全控制表單數據,確保 React state 是唯一數據源。
- 支持復雜的交互邏輯(如輸入時實時反饋)。
缺點
- 代碼量較多(需要為每個表單元素編寫事件處理函數)。
- 頻繁的 state 更新可能導致性能問題(大型表單需優化)。
非受控組件(Uncontrolled Components)
定義
表單元素的值由 ?DOM
自身管理,React
通過 ref
在需要時(如表單提交時)直接讀取 DOM
的值。用戶輸入不會觸發 React
的狀態更新。
關鍵特征
- 數據流:直接操作 DOM。
- 更新方式:通過 ref 手動獲取值。
- 值的來源:DOM 節點的當前值。
代碼示例
import { useRef } from 'react';function UncontrolledForm() {const inputRef = useRef(null);const handleSubmit = (e) => {e.preventDefault();console.log(inputRef.current.value); // 通過 ref 獲取 DOM 值};return (<form onSubmit={handleSubmit}><inputtype="text"ref={inputRef} // 使用 ref 關聯 DOM 節點defaultValue="初始值" // 僅初始化時設置默認值/><button type="submit">提交</button></form>);
}
適用場景
- 簡單表單(不需要實時驗證或動態交互)。
- 文件上傳(
<input type="file">
必須用非受控組件)。 - 性能敏感場景(避免頻繁 state 更新)。
優點
- 代碼簡潔,無需管理狀態。
- 性能更好(減少渲染次數)。
缺點
- 無法實時控制數據(如強制輸入格式)。
- 不符合 React 的“單一數據源”原則。
核心區別對比
特性 | 受控組件 | 非受控組件 |
---|---|---|
數據管理 | React state 控制 | DOM 自身管理 |
值同步 | 實時同步(onChange 事件) | 手動獲取(通過 ref) |
?初始值設置 | 通過 value 屬性 | 通過 defaultValue 屬性 |
表單驗證時機 | 輸入時實時驗證 | 提交時驗證 |
代碼復雜度 | 較高(需處理事件和狀態) | 較低(直接操作 DOM) |
性能 | 可能較低(頻繁渲染) | 較高 |
React 哲學匹配度 | 高(符合單向數據流) | 低(依賴 DOM 操作) |
如何選擇
- 優先受控組件:
大多數場景推薦使用受控組件,尤其是需要實時交互、驗證或動態表單時。
- 非受控組件的合理場景:
- 文件上傳(
<input type="file">
)。 - 性能敏感且無需實時反饋的表單。
- 與非 React 的第三方庫集成(如富文本編輯器)。
注意點
- 文件輸入:
<input type="file">
必須用非受控組件,因為其值只能由用戶設置(安全限制)。
- 默認值:
非受控組件用 defaultValue
或 defaultChecked
設置初始值(類似原生 HTML
)。
- 受控組件的性能優化:
大型表單中避免頻繁渲染,可通過防抖(debounce
)或 useCallback
優化事件處理函數。
總結
- ?受控組件:數據由 React 完全控制,適合復雜交互。
- 非受控組件:數據由 DOM 管理,適合簡單場景或性能敏感需求。
根據實際需求選擇,優先遵循 React
的單向數據流原則,僅在必要時使用非受控組件。