一、場景題:設計一個實時搜索輸入框,說明選擇依據
受控組件 vs 非受控組件
核心區別
特征 | 受控組件 | 非受控組件 |
---|---|---|
數據管理 | 由React狀態(state )控制 | 通過DOM元素(ref )直接訪問 |
更新時機 | 每次輸入觸發onChange | 提交時通過ref 獲取值 |
實時性 | 即時響應輸入 | 延遲獲取最終值 |
典型場景 | 需實時驗證/反饋的輸入 | 表單提交后處理 |
實時搜索輸入框設計
場景需求
? 用戶輸入時立即觸發搜索請求(需防抖優化)
? 輸入內容需要動態高亮匹配結果
? 支持清空輸入后重置搜索結果
方案選擇:受控組件
代碼實現:
import { useState, useEffect } from 'react';function SearchInput() {const [query, setQuery] = useState('');const [results, setResults] = useState([]);// 防抖處理(300ms延遲)useEffect(() => {const handler = setTimeout(() => {if (query) {fetchResults(query).then(setResults);} else {setResults([]);}}, 300);return () => clearTimeout(handler);}, [query]);return (<div><inputtype="text"value={query}onChange={(e) => setQuery(e.target.value)}placeholder="Search..."/><ul>{results.map((result) => (<li key={result.id}>{result.text}</li>))}</ul></div>);
}
選擇依據
-
實時反饋需求:
? 輸入內容需要立即觸發搜索邏輯(防抖優化避免頻繁請求)。
? 受控組件的onChange
可精準捕獲每次輸入變化,適合高頻交互。 -
狀態同步性:
? 搜索結果的渲染依賴當前輸入值(如query
清空時需同步清空結果)。
? 受控組件通過useState
保證UI與狀態嚴格同步。 -
React 18優化:
? 自動批處理(Automatic Batching)合并多次setQuery
導致的渲染,減少性能損耗。
?useTransition
可標記搜索為低優先級更新,避免輸入卡頓。
為何不選非受控組件?
-
延遲問題:
? 非受控組件需通過ref.current.value
手動獲取值,無法實時響應輸入變化。 -
防抖實現復雜:
? 需自行監聽input
事件并添加定時器,代碼冗余易出錯。 -
狀態追溯困難:
? 清空輸入框時需手動操作DOM(如ref.current.value = ""
),違背React數據流原則。
總結
? 優先受控組件:實時交互、狀態依賴型場景(搜索、表單驗證)。
? 選非受控組件:僅需最終結果的文件上傳、大型表單性能優化(如1000+字段)。
? React 18+優化:利用useDeferredValue
進一步降低高頻輸入的性能開銷:
const deferredQuery = useDeferredValue(query); // 延遲更新派生值
二、場景:自己實現一個非受控組件的案例
以下是一個簡單的非受控組件實現案例,通過 ref
直接訪問輸入框的值:
import { useRef } from 'react';function UncontrolledInput() {// 1. 創建ref引用const inputRef = useRef(null);// 2. 提交時獲取值const handleSubmit = (e) => {e.preventDefault();alert("輸入的值: " + inputRef.current.value);inputRef.current.value = ""; // 直接操作DOM清空輸入};return (<form onSubmit={handleSubmit}><input type="text" ref={inputRef} // 3. ref綁定到inputplaceholder="非受控輸入" /><button type="submit">提交</button></form>);
}
核心特點:
- 直接DOM操作:通過
inputRef.current.value
直接讀寫輸入框值 - 無狀態管理:無需
useState
控制輸入內容 - 適用場景:表單提交后只需最終值,無需實時驗證或中間狀態
對比受控組件優勢:
? 更少渲染:輸入過程不會觸發組件重渲染
? 代碼更簡:適合簡單表單(如一次性文件上傳)