10 câu hỏi có thể gặp khi phỏng vấn
Chọn theo kỹ năng và cấp của tin (ReactJS, Golang, Cloud (AWS, Azure, GCP)). Gợi ý trả lời do Drama Công Ty biên soạn để bạn ôn nhanh, không phải đề của công ty.
01Bạn chọn cách quản lý state thế nào: Context, Redux Toolkit, Zustand hay TanStack Query?ReactJS
Gợi ý trả lời
Ôn thêm câu hỏi ReactJS →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.
02Stale closure trong React là gì? Vì sao
setIntervaltronguseEffectcứ in ra giá trị cũ?ReactJSGợi ý trả lời
Ôn thêm câu hỏi ReactJS →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:
03React Server Components là gì? Trong Next.js App Router, khi nào dùng Server Component và khi nào cần
"use client"?ReactJS · SeniorGợi ý trả lời
Ôn thêm câu hỏi ReactJS →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á.04
deferhoạt động thế nào? Vòng lặpforkết hợp goroutine và closure có thay đổi gì từ Go 1.22?GolangGợi ý trả lời
Ôn thêm câu hỏi Golang →deferhoãn lời gọi hàm đến khi hàm bao ngoài kết thúc (kể cả khi panic), chạy theo thứ tự LIFO. Tham số của lời gọi được tính ngay lúc gặpdefer, không phải lúc chạy.for i := 0; i < 3; i++ { defer fmt.Println(i) // in 2, 1, 0 }- Đừng
defer f.Close()trong vòng lặp mở hàng nghìn file: chúng chỉ đóng khi hàm kết thúc. Tách thân vòng lặp thành hàm riêng.
Về vòng lặp: trước Go 1.22, biến vòng lặp dùng chung cho mọi lần lặp nên goroutine hay closure thường thấy giá trị cuối cùng. Từ Go 1.22, mỗi lần lặp có biến riêng (khi
go.modkhai báo 1.22 trở lên), nên lỗi này không còn.Người phỏng vấn muốn nghe: bạn biết thay đổi này phụ thuộc phiên bản trong
go.mod.- Đừng
05Goroutine leak là gì? Làm sao phát hiện và phòng tránh?Golang · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Golang →Goroutine leak là goroutine bị chặn mãi mãi và không bao giờ kết thúc, giữ theo bộ nhớ và tài nguyên nó tham chiếu. Số goroutine tăng dần theo thời gian là dấu hiệu rõ nhất.
Nguyên nhân hay gặp:
- Gửi vào channel mà bên nhận đã bỏ đi (ví dụ đã trả về vì timeout).
- Nhận từ channel không bao giờ được gửi hoặc đóng.
- Vòng lặp chạy nền không kiểm tra
ctx.Done(). - HTTP response không đóng
Body.
ch := make(chan Result, 1) // buffer 1: goroutine gửi xong vẫn thoát được go func() { ch <- slowCall() }() select { case r := <-ch: return r, nil case <-ctx.Done(): return Result{}, ctx.Err() }Phát hiện: theo dõi
runtime.NumGoroutine(), xem profile goroutine quanet/http/pprof, dùng thư việngoleaktrong test.Người phỏng vấn muốn nghe: mỗi goroutine bạn tạo phải có câu trả lời rõ ràng cho câu hỏi "nó kết thúc khi nào?".
06Thiết kế hạ tầng cho một web app cần chịu tải cao và sẵn sàng 99.9% trên cloud.Cloud (AWS, Azure, GCP) · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Cloud (AWS, Azure, GCP) →Trình bày theo luồng request và nói rõ điểm lỗi đơn được loại bỏ ở đâu.
- Biên: DNS, CDN cho nội dung tĩnh, WAF.
- Ứng dụng: load balancer L7 trước nhóm container/VM stateless trải nhiều AZ, auto scaling theo CPU hoặc số request.
- Dữ liệu: DB quản lý sẵn Multi-AZ, read replica cho đọc nhiều, Redis làm cache và session.
- Bất đồng bộ: queue cho việc nặng (gửi mail, xử lý ảnh).
- Vận hành: IaC, backup tự động có thử khôi phục, giám sát và alert theo SLO.
Người phỏng vấn muốn nghe: đánh đổi chi phí. 99.9% thường đủ với một region nhiều AZ; multi-region đắt và phức tạp hơn nhiều.
07Mộ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?ReactJS · Senior
Gợi ý trả lời
Ôn thêm câu hỏi ReactJS →Đ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;
08So sánh CSR, SSR, SSG và ISR. Lỗi hydration mismatch là gì và xử lý ra sao?ReactJS · Senior
Gợi ý trả lời
Ôn thêm câu hỏi ReactJS →- 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.
09React 19 có những gì mới đáng chú ý? Actions,
useActionStatevàuseOptimisticgiải quyết vấn đề gì?ReactJS · SeniorGợi ý trả lời
Ôn thêm câu hỏi ReactJS →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
10Kể về một thất bại hoặc sai lầm của bạn và bài học rút ra.Câu hỏi hành vi & văn hoá
Gợi ý trả lời
Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →Chọn sai lầm thật, có hậu quả vừa phải, nhận trách nhiệm rõ ràng, và nhấn mạnh việc bạn đã thay đổi sau đó.
Cấu trúc: chuyện gì xảy ra, phần lỗi của bạn, bạn khắc phục ngay thế nào, bài học và thay đổi lâu dài.
Câu mẫu: "Có lần em deploy một thay đổi cấu hình lên production vào chiều thứ Sáu mà không kiểm tra kỹ trên staging, làm một tính năng lỗi khoảng một giờ. Em báo ngay cho lead, rollback và viết báo cáo sự cố. Sau đó em đề xuất checklist trước deploy và quy ước hạn chế deploy cuối tuần; team áp dụng tới giờ."
Hay sai: kể một "thất bại" thực ra là khoe, đổ lỗi cho người khác, hoặc nói mình chưa từng thất bại.
Bạn đã phỏng vấn ở Grab (Vietnam) Ltd.?
Kể lại các vòng và câu hỏi đã gặp (ẩn danh) để người sau ôn đúng trọng tâm.
Chia sẻ kinh nghiệm phỏng vấn