Controlled (chuẩn React, recommend default): state cha giữ value, onChangeText cập nhật.
const [name, setName] = useState('')
<TextInput value={name} onChangeText={setName} />Lợi thế: validate/format on-the-fly, sync với store toàn cục, easy reset.
Uncontrolled: dùng defaultValue và onChangeText cache giá trị vào ref ngoài, không bind vào React state.
const valueRef = useRef('')
<TextInput
defaultValue=""
onChangeText={(t) => { valueRef.current = t }}
/>
// Lúc submit:
console.log(valueRef.current)RN không có inputRef.current.value như DOM web — phải tự cache qua onChangeText.
Thực tế RN, uncontrolled thuần ít gặp; pattern thường gặp hơn là react-hook-form dùng Controller ẩn ref bên trong → có cảm giác controlled cho user nhưng không re-render parent mỗi keystroke. Form lớn (10+ inputs) trên Android low-end thấy khác biệt rõ.
Ngoài ra, controlled <TextInput> từng có vấn đề race condition trên Android dưới Bridge cũ: user gõ 5 ký tự liên tục, JS state update async qua bridge, đôi khi caret nhảy ngược hoặc ký tự "rớt". New Architecture với JSI làm commit đồng bộ → vấn đề này biến mất ở RN 0.76+.