01React render và cập nhật DOM thế nào? Vì sao list cần
keyvà không nên dùng index làm key?JuniorGợi ý trả lời
Mỗi lần state hoặc props đổi, React gọi lại component để tạo cây element mới, so sánh với cây cũ (reconciliation), rồi chỉ cập nhật phần DOM thật sự thay đổi.
- Với list,
keycho React biết phần tử nào là phần tử nào giữa hai lần render. Key phải ổn định và duy nhất trong list, thường làidtừ dữ liệu. - Dùng index làm key chỉ ổn khi list không bao giờ chèn, xoá hay đổi thứ tự.
Hay sai: dùng index cho list có thể xoá hoặc sắp xếp. React ghép nhầm state của item cũ sang item mới: ô input giữ nội dung của dòng đã bị xoá, checkbox tick sai dòng.
Mẹo hay được hỏi thêm: đổi
keycủa một component là cách chủ động reset toàn bộ state của nó.- Với list,
02Props và state khác nhau thế nào? Vì sao không được sửa trực tiếp state?Junior
Gợi ý trả lời
Props là dữ liệu cha truyền xuống, component con chỉ đọc. State là dữ liệu component tự quản lý; đổi state sẽ khiến component render lại.
- React so sánh state cũ và mới bằng tham chiếu (
Object.is). Sửa trực tiếpstate.items.push(x)thì tham chiếu không đổi, React có thể không render lại, và các tối ưu nhưmemocũng hỏng. - Luôn tạo object hoặc array mới:
setItems(prev => [...prev, newItem]); setUser(prev => ({ ...prev, name: "An" }));setStatekhông cập nhật biến ngay trong lần render hiện tại. React gom nhiều lần set lại (batching) rồi mới render.
Hay sai: gọi
setCount(count + 1)ba lần liên tiếp và mong tăng 3. Kết quả chỉ tăng 1; muốn tăng 3 phải dùng dạng hàmsetCount(c => c + 1).- React so sánh state cũ và mới bằng tham chiếu (
03
useEffectdùng để làm gì? Dependency array và hàm cleanup hoạt động ra sao?JuniorGợi ý trả lời
useEffectdùng để đồng bộ component với hệ thống bên ngoài: subscribe sự kiện, kết nối WebSocket, gọi thư viện không phải React, gọi API.- Không có dependency array: chạy sau mỗi lần render.
[]: chạy sau lần mount đầu tiên.[a, b]: chạy lại khiahoặcbđổi.- Hàm return là cleanup, chạy trước lần effect kế tiếp và khi unmount.
useEffect(() => { const id = setInterval(tick, 1000); return () => clearInterval(id); }, []);Ở development, Strict Mode cố ý chạy effect hai lần để bạn phát hiện thiếu cleanup.
Hay sai: dùng effect để tính dữ liệu dẫn xuất từ state/props (
setFullName(first + last)). Hãy tính thẳng trong lúc render; effect thừa gây render hai lần và dễ lệch dữ liệu.04Controlled component và uncontrolled component khác nhau thế nào? Khi nào dùng loại nào?Junior
Gợi ý trả lời
Controlled: giá trị input nằm trong state React, mọi thay đổi đi qua
onChange. Uncontrolled: DOM tự giữ giá trị, bạn đọc khi cần quarefhoặc khi form submit.<input value={name} onChange={e => setName(e.target.value)} /> <input defaultValue="An" name="name" />- Controlled hợp khi cần validate ngay khi gõ, định dạng giá trị, hoặc ô này phụ thuộc ô kia.
- Uncontrolled đơn giản hơn, ít render hơn; hợp với form lớn hoặc khi dùng thư viện như React Hook Form. React 19 còn hỗ trợ truyền hàm vào
<form action>và đọc dữ liệu bằngFormData.
Hay sai: chuyển một input từ
value={undefined}sang có giá trị, khiến React cảnh báo đổi từ uncontrolled sang controlled. Khởi tạo state bằng""thay vìundefined.05Khi nào nên dùng
useMemo,useCallbackvàReact.memo? Dùng tràn lan có sao không?Gợi ý trả lời
Cả ba dùng để tránh tính toán hoặc render lại không cần thiết:
useMemo: nhớ kết quả của phép tính tốn kém.useCallback: nhớ hàm, để tham chiếu không đổi giữa các lần render.React.memo: bỏ qua render component con nếu props không đổi (so sánh nông).
Chúng thường phải đi cùng nhau: truyền hàm mới mỗi lần render vào component đã
memothìmemovô tác dụng.Dùng tràn lan làm code khó đọc, tốn công so sánh dependency, và dễ sai khi thiếu dependency. Chỉ nên dùng khi đã đo bằng React DevTools Profiler và thấy chậm, hoặc khi giá trị đó là dependency của effect.
React Compiler có thể tự thêm memo khi build, giảm nhu cầu viết tay.
Người phỏng vấn muốn nghe: trước khi memo, hãy thử đưa state xuống thấp hơn hoặc truyền component qua
childrenđể giảm phạm vi render lại.06Custom hook là gì? Các quy tắc của hooks là gì và vì sao có chúng?
Gợi ý trả lời
Custom hook là hàm bắt đầu bằng
use, dùng các hook khác bên trong, để tái sử dụng logic có state giữa nhiều component (không chia sẻ state, mỗi component có bản riêng).function useDebounce(value, ms) { const [debounced, setDebounced] = useState(value); useEffect(() => { const id = setTimeout(() => setDebounced(value), ms); return () => clearTimeout(id); }, [value, ms]); return debounced; }Quy tắc: chỉ gọi hook ở cấp cao nhất của component hoặc custom hook; không gọi trong
if, vòng lặp hay saureturnsớm. Lý do: React nhận diện từng hook theo thứ tự gọi, đổi thứ tự là state bị ghép nhầm.Ngoại lệ: hook
use()của React 19 được gọi trong điều kiện.Người phỏng vấn muốn nghe: bạn bật ESLint plugin
react-hooksđể bắt các lỗi này tự động.07Bạn chọn cách quản lý state thế nào: Context, Redux Toolkit, Zustand hay TanStack Query?
Gợi ý trả lời
Trước hết phân loại state:
- Server state (dữ liệu từ API): dùng TanStack Query hoặc SWR. Chúng lo cache, loading, refetch, đồng bộ. Phần lớn "global state" trong app thực ra thuộc loại này.
- UI state cục bộ:
useState/useReducerngay trong component. - State trên URL (bộ lọc, trang): để trên query string, chia sẻ link được.
- Client state toàn cục thật sự (giỏ hàng, theme, user đang đăng nhập): Context nếu ít thay đổi; Zustand hoặc Redux Toolkit nếu thay đổi thường xuyên hoặc logic phức tạp.
Redux Toolkit hợp khi team lớn cần quy ước chặt và DevTools mạnh. Zustand gọn nhẹ hơn.
Hay sai: gom state hay thay đổi vào một Context lớn. Mọi component dùng Context đó render lại mỗi lần bất kỳ giá trị nào đổi. Hãy tách Context, hoặc dùng thư viện có selector.
08Stale closure trong React là gì? Vì sao
setIntervaltronguseEffectcứ in ra giá trị cũ?Gợi ý trả lời
Mỗi lần render tạo ra hàm mới, "chụp" lại props và state của lần render đó. Nếu effect chỉ chạy một lần, callback bên trong mãi thấy giá trị lúc mount.
useEffect(() => { const id = setInterval(() => { setCount(count + 1); // count luôn là 0 }, 1000); return () => clearInterval(id); }, []);Cách sửa:
- Dùng functional update:
setCount(c => c + 1), không cần đọccount. - Khai báo đúng dependency (effect chạy lại khi giá trị đổi, nhớ cleanup).
- Với giá trị chỉ cần đọc mới nhất mà không muốn chạy lại effect: lưu vào
useRef.
Hay sai: tắt cảnh báo
exhaustive-depscủa ESLint cho xong. Cảnh báo đó thường chính là dấu hiệu stale closure.- Dùng functional update:
09React Server Components là gì? Trong Next.js App Router, khi nào dùng Server Component và khi nào cần
"use client"?SeniorGợi ý trả lời
Server Component chạy trên server (lúc build hoặc lúc request), có thể
awaitdữ liệu trực tiếp từ DB hoặc API, và không gửi JavaScript của nó xuống trình duyệt. Trong App Router, component mặc định là Server Component.- Dùng Server Component cho: lấy dữ liệu, render nội dung tĩnh, dùng secret hoặc thư viện nặng chỉ cần ở server.
- Cần
"use client"khi dùng state, effect, sự kiện (onClick), API trình duyệt (window,localStorage). "use client"đánh dấu ranh giới: mọi module được import từ file đó đều vào bundle client.- Server Component có thể truyền Server Component khác vào Client Component qua
children. - Props truyền từ server sang client phải serialize được (không truyền hàm thường; Server Action thì được).
Hay sai: đặt
"use client"ở layout gốc, biến cả app thành client và mất lợi ích. Hãy đẩy phần tương tác xuống các component lá.10Một màn hình React (bảng dữ liệu lớn, ô tìm kiếm) bị giật lag. Bạn tìm và xử lý thế nào?Senior
Gợi ý trả lời
Đo trước: React DevTools Profiler (bật "Highlight updates" và xem component nào render nhiều, tốn bao lâu) và tab Performance của Chrome để tìm long task.
Các hướng xử lý thường gặp:
- Giảm phạm vi render: đưa state xuống gần nơi dùng; tách component;
memocác hàng của bảng với props ổn định. - Virtualization cho list hoặc bảng dài: chỉ render các dòng đang hiện (TanStack Virtual, react-window).
- Ưu tiên cập nhật:
useDeferredValuehoặcuseTransitionđể ô input phản hồi ngay, còn việc lọc bảng chạy sau và có thể bị ngắt. - Tính toán nặng:
useMemo, hoặc chuyển sang Web Worker. - Bundle lớn:
lazy()vàSuspenseđể tách code theo route hoặc theo modal.
Người phỏng vấn muốn nghe: bạn tìm ra nguyên nhân cụ thể (render thừa, DOM quá nhiều, JS nặng) rồi mới chọn kỹ thuật, không rải
useMemokhắp nơi.- Giảm phạm vi render: đưa state xuống gần nơi dùng; tách component;
11So sánh CSR, SSR, SSG và ISR. Lỗi hydration mismatch là gì và xử lý ra sao?Senior
Gợi ý trả lời
- CSR: trình duyệt tải JS rồi mới render; nội dung hiện chậm, kém cho SEO.
- SSR: server render HTML cho mỗi request. Dữ liệu luôn mới, tốn tài nguyên server.
- SSG: render sẵn lúc build. Rất nhanh, hợp nội dung ít đổi.
- ISR / revalidate: trang tĩnh được làm mới định kỳ hoặc theo sự kiện.
Hydration là bước React gắn sự kiện vào HTML do server render. Mismatch xảy ra khi lần render đầu ở client khác HTML từ server:
- Dùng
Date.now(),Math.random(), múi giờ,windowhoặclocalStoragetrong lúc render. - HTML lồng sai (
<div>trong<p>), extension trình duyệt sửa DOM.
Cách sửa: chuyển phần chỉ có ở client vào
useEffect, hoặc render component đó chỉ ở client; định dạng ngày giờ bằng múi giờ cố định.Người phỏng vấn muốn nghe: bạn chọn cách render theo từng trang, dựa trên độ tươi dữ liệu và nhu cầu SEO.
12React 19 có những gì mới đáng chú ý? Actions,
useActionStatevàuseOptimisticgiải quyết vấn đề gì?SeniorGợi ý trả lời
React 19 tập trung vào việc xử lý thao tác bất đồng bộ (gửi form, mutation) gọn hơn:
- Actions: truyền hàm async vào
<form action={fn}>hoặc chạy trongstartTransition. React tự theo dõi trạng thái pending, lỗi, và reset form. useActionState: giữ kết quả của action (thông báo lỗi, dữ liệu trả về) và cờisPending.useFormStatus: component con (nút submit) đọc trạng thái pending của form cha mà không cần truyền props.useOptimistic: hiện kết quả ngay (like, thêm comment) trong lúc chờ server, tự quay về nếu lỗi.use(): đọc Promise hoặc Context, gọi được trong điều kiện.refđược truyền như prop thường, ít cầnforwardRef.
Người phỏng vấn muốn nghe: những API này bỏ bớt code tự quản lý
isLoading,errorvà rollback, và kết hợp tự nhiên với Server Actions trong Next.js.- Actions: truyền hàm async vào
Gặp câu hỏi khác khi phỏng vấn? Kể lại ẩn danh để người sau ôn đúng trọng tâm, hoặc xem câu hỏi thật hay gặp ở nhiều công ty.