Một câu hỏi phỏng vấn tốt không nhất thiết yêu cầu nhớ tên nhiều hook. Đôi khi chỉ cần một ô tìm kiếm trả kết quả chậm một ký tự là đủ để quan sát cách bạn đọc code, giải thích mô hình state và kiểm tra bản sửa.
Bài tập này dành cho ứng viên junior đến middle đã dùng function component. Ví dụ chạy trong React web, nhưng lập luận về state cũng hữu ích khi viết React Native. Tài liệu được đối chiếu ngày 21/10/2026.
1. Đọc lỗi trước khi sửa
Giả sử component có query, filtered và một mảng products có sẵn. Event handler được viết như sau:
function handleChange(event) {
setQuery(event.target.value);
setFiltered(
products.filter(product => product.name.includes(query))
);
}
Người phỏng vấn hỏi: “Vì sao kết quả đang dùng từ khóa trước đó?”. Bạn không nên chỉ nói “setState bất đồng bộ” rồi thêm một khoảng chờ. React mô tả state như snapshot: handler đang chạy nhìn thấy state của render đã tạo ra nó. Gọi setter yêu cầu render tiếp theo, không thay giá trị biến query trong handler hiện tại.
Một câu trả lời rõ là: “Trong lần gọi này, event.target.value là input mới, còn query là giá trị của render trước. Vì thế phép lọc dùng mốc cũ”.
2. Bản sửa ngắn và bản sửa tốt hơn
Bạn có thể dùng một biến nextQuery rồi lọc theo biến đó. Cách này sửa biểu hiện ở handler, nhưng vẫn phải giữ filtered đồng bộ với cả query lẫn dữ liệu nguồn.
Với danh sách nhỏ, hãy chỉ lưu input người dùng. Danh sách sau lọc có thể tính từ các giá trị hiện tại. Hướng dẫn chọn cấu trúc state khuyến khích tránh state dư thừa có thể tính từ props hoặc state khác.
Ví dụ hoàn chỉnh cho một component:
import { useState } from 'react';
const products = [
{ id: 'keyboard', name: 'Bàn phím', available: true },
{ id: 'mouse', name: 'Chuột', available: false },
{ id: 'monitor', name: 'Màn hình', available: true },
];
export default function ProductSearch() {
const [query, setQuery] = useState('');
const [onlyAvailable, setOnlyAvailable] = useState(false);
const normalizedQuery = query.trim().toLocaleLowerCase('vi');
const visibleProducts = products.filter(product => {
const matchesText = product.name
.toLocaleLowerCase('vi')
.includes(normalizedQuery);
return matchesText && (!onlyAvailable || product.available);
});
return (
<section>
<label>
Tên sản phẩm
<input
value={query}
onChange={event => setQuery(event.target.value)}
/>
</label>
<label>
<input
type="checkbox"
checked={onlyAvailable}
onChange={event => setOnlyAvailable(event.target.checked)}
/>
Chỉ hiện sản phẩm còn hàng
</label>
<p>{visibleProducts.length} kết quả</p>
<ul>
{visibleProducts.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</section>
);
}
Phép chuẩn hóa này bỏ khoảng trắng hai đầu và không phân biệt chữ hoa/thường. Nó chưa bỏ dấu tiếng Việt: nhập “ban” không được cam kết khớp “Bàn”. Nêu rõ giới hạn như vậy thể hiện bạn phân biệt một bản sửa state với toàn bộ yêu cầu tìm kiếm.
3. Chứng minh bằng tình huống cụ thể
Với dữ liệu trên, các kết quả mong đợi là:
| Thao tác | Kết quả mong đợi |
|---|---|
| Mở component, từ khóa rỗng | 3 sản phẩm |
| Nhập “bàn” | Chỉ Bàn phím |
| Nhập “CHUỘT” | Chỉ Chuột |
| Giữ từ khóa “CHUỘT”, bật còn hàng | 0 sản phẩm |
| Xóa từ khóa, vẫn bật còn hàng | Bàn phím và Màn hình |
Đây là các assertion chức năng có ý nghĩa hơn việc kiểm tra component có đúng hai lời gọi useState. Chúng kiểm tra điều người dùng nhìn thấy và có thể giữ nguyên khi cách triển khai thay đổi.
4. Câu hỏi mở rộng về nhiều lần cập nhật
Người phỏng vấn có thể chuyển sang đoạn sau:
setAttempts(attempts + 1);
setAttempts(attempts + 1);
Hai biểu thức cùng đọc một snapshot. Nếu ý định là tăng hai lần từ giá trị đang chờ, dùng hai updater:
setAttempts(current => current + 1);
setAttempts(current => current + 1);
Tài liệu hàng đợi cập nhật state giải thích cách React xử lý các updater. Đừng biến mẹo này thành quy tắc “mọi setter đều phải dùng callback”: chọn dạng cập nhật theo việc giá trị mới có phụ thuộc giá trị trước đó hay không.
5. Cách tự đánh giá câu trả lời
Một câu trả lời tốt chỉ ra giá trị cũ được đọc ở đâu, đề xuất bản sửa ít state hơn và kiểm tra được hành vi của bản sửa. Khi được hỏi về dữ liệu lớn, bạn có thể nói cần đo chi phí lọc trước khi thêm memoization hoặc chuyển tìm kiếm sang lớp dữ liệu.
Đừng tự thêm debounce, global store và request tìm kiếm vào một bài toán ba phần tử. Hãy xử lý lỗi được giao trước, rồi nêu hướng mở rộng theo yêu cầu. Kỹ năng được quan sát là khả năng giải thích quyết định bằng dữ liệu và hành vi cụ thể.





