Chọn inputMode="numeric" giúp mở bàn phím phù hợp, nhưng không đủ để bảo đảm dữ liệu là số nguyên hợp lệ. Người dùng còn có thể dán nội dung hoặc dùng bàn phím phần cứng. Ngay cả chuỗi chỉ chứa chữ số cũng có thể nằm ngoài khoảng mà sản phẩm cho phép.
Bài đối chiếu tài liệu React Native 0.88 ngày 29/10/2026. Ví dụ là form cục bộ nhận số lượng từ 1 đến 999, dùng JavaScript với JSX. Hàm kiểm tra dữ liệu được chạy bằng Node.js 24.18.1; phần UI đã rà theo API nhưng chưa build hoặc thử trên Android/iOS.
Giữ bản nháp nhập liệu là string
TextInput.value nhận string. Khi người dùng xóa hết để nhập lại, chuỗi rỗng là một trạng thái chỉnh sửa bình thường. Nếu lập tức dùng Number(text) làm state, bạn sẽ biến rỗng thành 0 và khó phân biệt chưa nhập với đã nhập số không.
Trong form này, ta giữ text riêng, chỉ chuyển sang số ở thời điểm xác nhận. Quy tắc demo là nhận từ một đến ba chữ số ASCII, sau đó kiểm tra khoảng 1–999. Chuỗi có dấu âm, dấu thập phân, ký hiệu số mũ hoặc khoảng trắng đều bị từ chối rõ ràng.
function parseQuantity(text) {
if (!/^[0-9]{1,3}$/.test(text)) return null;
const value = Number(text);
return value >= 1 && value <= 999 ? value : null;
}
console.log(parseQuantity('12'));
console.log(parseQuantity(''));
console.log(parseQuantity('1e2'));
console.log(parseQuantity('000'));
console.log(parseQuantity('007'));
Kết quả là 12, null, null, null, 7. Trong nghiệp vụ số lượng, 007 được hiểu thành 7 là một lựa chọn của ví dụ. Với mã định danh cần giữ số 0 đầu, không áp dụng phép chuyển số này. Hãy giữ string theo schema của trường đó.
Ghép vào một form có phản hồi lỗi
Đặt hàm parseQuantity ở trên trong cùng file với component dưới đây. Ví dụ không gửi request và không lưu dữ liệu lâu dài; nút chỉ hiển thị kết quả đã xác nhận trong bộ nhớ.
import React, {useState} from 'react';
import {Button, ScrollView, Text, TextInput} from 'react-native';
export default function QuantityForm() {
const [text, setText] = useState('');
const [error, setError] = useState('');
const [accepted, setAccepted] = useState(null);
function changeText(next) {
setText(next);
setError('');
setAccepted(null);
}
function submit() {
const value = parseQuantity(text);
if (value === null) {
setError('Nhập số nguyên từ 1 đến 999 bằng chữ số 0–9.');
setAccepted(null);
return;
}
setError('');
setAccepted(value);
}
return (
<ScrollView
keyboardShouldPersistTaps="handled"
contentContainerStyle={{padding: 24, gap: 12}}>
<Text>Số lượng (1–999)</Text>
<TextInput
value={text}
onChangeText={changeText}
inputMode="numeric"
maxLength={3}
accessibilityLabel="Số lượng, từ 1 đến 999"
style={{borderWidth: 1, padding: 12, fontSize: 18}}
/>
{error !== '' && (
<Text accessibilityLiveRegion="polite">{error}</Text>
)}
<Button title="Xác nhận số lượng" onPress={submit} />
{accepted !== null && <Text>Đã xác nhận: {accepted}</Text>}
</ScrollView>
);
}
Khi input đổi, kết quả xác nhận cũ được xóa để tránh hiển thị một số không còn tương ứng với nội dung đang sửa. error cũng chỉ là phản hồi cho lần submit trước, không ép người dùng nhập đủ ngay từ ký tự đầu.
TextInput reference ghi inputMode quyết định bàn phím và ưu tiên hơn keyboardType. Trong ví dụ chỉ đặt một prop này để ý định rõ ràng. maxLength giới hạn độ dài native, nhưng một chuỗi ba ký tự như 1e2 vẫn cần parser kiểm tra.
Vì sao không lọc mọi ký tự ngay khi gõ?
Bạn có thể thiết kế kiểu nhập chỉ nhận chữ số, nhưng phải kiểm tra trải nghiệm con trỏ, paste và quá trình soạn thảo trên bàn phím đích. Ví dụ này giữ nguyên bản nháp trong giới hạn độ dài rồi giải thích lỗi lúc xác nhận, giúp quy tắc dễ theo dõi.
Đừng dùng parseInt như phép kiểm tra toàn chuỗi: nó có thể nhận tiền tố số rồi bỏ phần sau. Cũng không dùng onKeyPress làm hàng rào duy nhất, vì sự kiện từng phím không đại diện mọi nguồn thay đổi nội dung. Parser cần được gọi ở đường đi submit dù bàn phím trông như chỉ có số.
Kiểm tra cả hàm và thao tác thật
Với hàm thuần, thử 1, 999, 0, 1000, chuỗi rỗng, 1.5, -2, 1e2, khoảng trắng và chữ số ngoài ASCII. Quy tắc hiện tại cố tình chỉ nhận 0–9; nếu sản phẩm hỗ trợ kiểu số địa phương, cần một hợp đồng chuẩn hóa khác và test riêng.
Trên thiết bị, thử xóa hết, paste, nhập ở giữa chuỗi, bàn phím phần cứng và nhấn nút khi bàn phím còn mở. Native maxLength có thể giới hạn nội dung được dán trước khi parser nhìn thấy nó. Vì vậy đừng dùng test riêng của hàm để tuyên bố đã kiểm tra toàn bộ hành vi paste.
Thử TalkBack và VoiceOver để biết nhãn và lỗi có thể được tìm thấy. accessibilityLiveRegion trong Accessibility reference áp dụng cho Android; không coi nó là bảo đảm tự đọc lỗi trên iOS. Lỗi vẫn hiện bằng text để người dùng có thể quay lại đọc.
Giới hạn khi nối backend
State được quản lý theo useState, không phải dữ liệu đã được server chấp nhận. Khi thêm API, server vẫn phải kiểm tra kiểu, khoảng, quyền và điều kiện tồn kho theo nghiệp vụ. Một form hợp lệ tại máy không bảo đảm trạng thái phía server chưa thay đổi.
Giữ ba bước rõ ràng: bản nháp string, giá trị đã parse và kết quả nghiệp vụ. Bàn phím giúp thao tác dễ hơn; parser và kiểm tra phía server mới xác định dữ liệu nào được phép xử lý.




