Câu hỏi phỏng vấn vị trí ReactJS


  • Lời giải: React là thư viện UI render theo thành phần (Component-based). Đặc điểm quan trọng nhất là Declarative (Khai báo): Bạn chỉ cần mô tả giao diện trông như thế nào ứng với từng trạng thái, React sẽ tự lo việc cập nhật DOM.

  • Code Demo:

JavaScript
// Thay vì dùng JS thuần để appendChild (Imperative)
// Ta khai báo giao diện dựa trên biến 'isLoggedIn'
function App({ isLoggedIn }) {
  return (
    <div>
      {isLoggedIn ? <h1>Chào mừng quay lại!</h1> : <h1>Vui lòng đăng nhập.</h1>}
    </div>
  );
}
  • Lời giải: JSX là cú pháp mở rộng cho phép viết HTML trong JS. Trình duyệt không hiểu được JSX; nó cần các công cụ như Babel để biên dịch về React.createElement().

  • Code Demo:

JavaScript
// Cách chúng ta viết (JSX)
const element = <h1 className="greet">Hello</h1>;

// Cách React thực thi (Sau khi Babel biên dịch)
const element = React.createElement('h1', { className: 'greet' }, 'Hello');
  • Lời giải: Real DOM cập nhật rất chậm vì phải vẽ lại toàn bộ cây khi có thay đổi. Virtual DOM là bản sao nhẹ bằng JS. React so sánh bản sao cũ và mới (Diffing), sau đó chỉ cập nhật những phần khác biệt lên Real DOM (Reconciliation).

  • Code Demo: (Mô phỏng cơ chế Diffing)

JavaScript
// Lần 1: <ul><li>Item 1</li></ul>
// Lần 2: <ul><li>Item 1</li><li>Item 2</li></ul>
// React nhận ra chỉ có <li>Item 2</li> là mới và chỉ thêm đúng node đó.
  • Lời giải: Class Component dùng class, có this và lifecycle. Functional Component là hàm, dùng Hooks để quản lý state, cú pháp ngắn gọn và hiện đại hơn.

  • Code Demo:

JavaScript
// Functional (Modern)
const Greet = () => <h1>Hello World</h1>;

// Class (Old school)
class Greet extends React.Component {
  render() { return <h1>Hello World</h1>; }
}
  • Lời giải: Props là dữ liệu truyền từ cha xuống con. Props là Read-only (Bất biến). Con không được phép sửa trực tiếp props nhận được.

  • Code Demo:

JavaScript
function Child(props) {
  // props.name = "New Name"; // SAI: Sẽ gây lỗi hoặc không có tác dụng
  return <h1>Hello, {props.name}</h1>;
}
  • Lời giải: State là dữ liệu nội bộ của component, có thể thay đổi theo thời gian (ví dụ: người dùng nhập liệu). Khi State thay đổi, component sẽ re-render.

  • Code Demo:

JavaScript
function Counter() {
  const [count, setCount] = useState(0); // Khởi tạo state
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
  • Lời giải: Vì React cần thông qua hàm setState hoặc hàm set của Hook để biết rằng dữ liệu đã đổi, từ đó mới kích hoạt quá trình re-render UI. Cập nhật trực tiếp sẽ không làm UI thay đổi.

  • Code Demo:

JavaScript
const [user, setUser] = useState({ name: 'Diep' });

// SAI
// user.name = 'Admin'; 

// ĐÚNG
setUser({ ...user, name: 'Admin' }); 
  • Lời giải: Khi hai hoặc nhiều component con cần dùng chung một dữ liệu và đồng bộ với nhau, ta đưa state đó lên cha chung gần nhất của chúng.

  • Code Demo:

JavaScript
function Parent() {
  const [text, setText] = useState("");
  return (
    <>
      <Input childText={text} onTextChange={setText} />
      <Display childText={text} />
    </>
  );
}
  • Lời giải: Là những hàm cho phép "móc" vào state và lifecycle của React từ Functional Component. Bắt đầu bằng chữ use.

  • Code Demo: useState, useEffect, useMemo...

  • Lời giải: 1. Chỉ gọi ở cấp cao nhất của hàm (không gọi trong vòng lặp, điều kiện). 2. Chỉ gọi trong React Function.

  • Code Demo:

JavaScript
function MyComponent() {
  if (condition) {
     // const [data, setData] = useState(); // SAI: Vi phạm quy tắc 1
  }
}

  • Lời giải: Dùng để xử lý Side Effect (gọi API, subscription).

  • Code Demo:

JavaScript
useEffect(() => {
  // Chạy sau mỗi lần render
});

useEffect(() => {
  // Chỉ chạy 1 lần duy nhất (componentDidMount)
}, []);

useEffect(() => {
  // Chạy khi 'id' thay đổi
}, [id]);
  • Lời giải: Trả về một hàm bên trong useEffect. Hàm này chạy trước khi component bị hủy (unmount) hoặc trước khi chạy lại effect mới.

  • Code Demo:

JavaScript
useEffect(() => {
  const timer = setInterval(() => console.log('Tick'), 1000);
  return () => clearInterval(timer); // Cleanup tránh leak memory
}, []);
  • Lời giải: Dùng để lưu trữ một giá trị bất biến qua các lần render mà không gây re-render khi giá trị đó thay đổi (ví dụ: lưu timer ID, giá trị cũ của props).

  • Code Demo:

JavaScript
const countRef = useRef(0);
const handleIncr = () => {
  countRef.current++; // Giá trị tăng nhưng UI không load lại ngay
};
  • Lời giải: useMemo dùng để cache kết quả của một hàm (một giá trị). useCallback dùng để cache chính định nghĩa hàm đó.

  • Code Demo:

JavaScript
const cachedValue = useMemo(() => expensiveCompute(a), [a]);
const cachedFn = useCallback(() => doSomething(a), [a]);
  • Lời giải: Tránh tình trạng "Prop Drilling" (phải truyền props qua quá nhiều tầng trung gian không cần thiết).

  • Code Demo: (Xem lại ví dụ Context ở câu 17 phần trước).

  • Lời giải: Khi state có cấu trúc phức tạp (object nhiều tầng) hoặc logic cập nhật state tiếp theo phụ thuộc vào state trước đó một cách phức tạp.

  • Code Demo:

JavaScript
const [state, dispatch] = useReducer(reducer, { count: 0 });
// dispatch({ type: 'increment' });
  • Lời giải: Để React định danh duy nhất từng phần tử, giúp quá trình Diffing diễn ra chính xác (biết cái nào bị xóa, cái nào mới thêm).

  • Code Demo:

JavaScript
{items.map(item => <li key={item.id}>{item.text}</li>)}
  • Lời giải: Controlled: State React quản lý value của input. Uncontrolled: DOM tự quản lý value, ta lấy qua ref.

  • Code Demo (Controlled):

JavaScript
<input value={val} onChange={(e) => setVal(e.target.value)} />
  • Lời giải: Là HOC giúp ngăn chặn component re-render nếu props của nó không thay đổi.

  • Code Demo:

JavaScript
const MyChild = React.memo(({ name }) => {
  console.log("Render con");
  return <div>{name}</div>;
});
  • Lời giải: Gom nhóm các phần tử mà không thêm thẻ HTML thật vào DOM, giữ cho cấu trúc HTML sạch và tránh lỗi CSS (như trong Flexbox/Grid).

  • Lời giải: HOC là một hàm nhận vào một Component và trả về một Component mới đã được "tăng cường" tính năng (như phân quyền, loading).

  • Code Demo:

JavaScript
const withLogger = (WrappedComponent) => {
  return (props) => {
    console.log("Component renders with props:", props);
    return <WrappedComponent {...props} />;
  };
};
const EnhancedButton = withLogger(({label}) => <button>{label}</button>);
  • Lời giải: Kỹ thuật chia sẻ logic giữa các component bằng cách dùng một prop có giá trị là một hàm (function) để xác định nội dung render.

  • Code Demo:

JavaScript
const MouseTracker = ({ render }) => {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  return <div onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>
    {render(pos)}
  </div>;
};
// Sử dụng: <MouseTracker render={(p) => <h1>X: {p.x}, Y: {p.y}</h1>} />
  • Lời giải: Là Class Component dùng để "bắt" lỗi JavaScript ở bất kỳ đâu trong cây component con và hiển thị giao diện dự phòng thay vì để toàn bộ app bị trắng trang.

  • Code Demo:

JavaScript
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError() { return { hasError: true }; }
  render() {
    if (this.state.hasError) return <h1>Đã có lỗi xảy ra!</h1>;
    return this.props.children;
  }
}
  • Lời giải: Dùng để render một component vào một node DOM nằm ngoài cấu trúc phân cấp hiện tại (thường dùng cho Modal, Popover).

  • Code Demo:

JavaScript
const Modal = ({ children }) => {
  return ReactDOM.createPortal(
    <div className="modal">{children}</div>,
    document.getElementById('modal-root')
  );
};
  • Lời giải: Context API tích hợp sẵn, phù hợp cho app vừa/nhỏ hoặc dữ liệu ít thay đổi (Locale, Theme). Redux mạnh mẽ hơn cho app lớn, cần quản lý state phức tạp, có công cụ Debug (DevTools) và Middleware (Thunk/Saga).

  • Lời giải: Giúp chia nhỏ file JS của app thành các mảnh nhỏ, chỉ tải khi cần thiết để tăng tốc độ load trang đầu tiên.

  • Code Demo:

JavaScript
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
  return (
    <Suspense fallback={<div>Đang tải...</div>}>
      <LazyComponent />
    </Suspense>
  );
}
  • Lời giải: Là công cụ để đo lường tần suất render và "chi phí" render của các component, giúp tìm ra điểm nghẽn hiệu năng.

  • Code Demo:

JavaScript
<Profiler id="App" onRender={(id, phase, actualDuration) => console.log(id, actualDuration)}>
  <MyComponent />
</Profiler>
  • Lời giải: React.memo bọc cả Component để tránh re-render. useMemo bọc một giá trị/tính toán bên trong component để tránh tính toán lại.

  • Lời giải: React tạo ra một lớp bọc (wrapper) xung quanh các sự kiện gốc của trình duyệt để đảm bảo sự kiện hoạt động giống nhau trên mọi trình duyệt (Cross-browser).

  • Lời giải: useEffect gom nhóm các logic liên quan vào một chỗ (ví dụ: subcribe và unsubcribe), thay vì phải chia tách ra componentDidMountcomponentWillUnmount.


  • Lời giải: Link dùng cho điều hướng khai báo (click vào link). useNavigate dùng cho điều hướng lập trình (sau khi gọi API thành công thì chuyển trang).

  • Code Demo:

JavaScript
const navigate = useNavigate();
const handleLogin = () => {
  // Logic...
  navigate('/dashboard');
};
  • Lời giải: Là bộ công cụ chuẩn để viết Redux hiện đại, giúp giảm bớt "boilerplate code" (code rườm rà) và tích hợp sẵn Immer (viết code mutable nhưng thực thi immutable).

  • Code Demo:

JavaScript
const counterSlice = createSlice({
  name: 'counter',
  initialState: 0,
  reducers: { increment: state => state + 1 }
});
  • Lời giải: axios tự động parse JSON, hỗ trợ interceptors, timeout và chạy được trên cả trình duyệt lẫn Node.js. fetch là API gốc của trình duyệt, cần parse JSON thủ công.

  • Lời giải: Là hàm JS bắt đầu bằng use, cho phép tách logic xử lý (như fetch data, toggle) ra khỏi UI để tái sử dụng.

  • Code Demo:

JavaScript
function useToggle(initial = false) {
  const [val, setVal] = useState(initial);
  const toggle = () => setVal(!val);
  return [val, toggle];
}
  • Lời giải: Giúp tối ưu hiệu năng vì không re-render component mỗi khi gõ phím (Uncontrolled component approach) và xử lý validation dễ dàng.

  • Lời giải: Server render HTML đầy đủ nội dung rồi gửi về trình duyệt. Giúp SEO tốt hơn và người dùng thấy nội dung nhanh hơn (thường dùng Next.js).

  • Lời giải: Sau khi SSR gửi HTML tĩnh xuống, React "đổ" logic (event listener) vào các thẻ HTML đó để trang web có thể tương tác được.

  • Lời giải: Nó double-invoke (gọi 2 lần) các effect và render trong môi trường Dev để giúp lập trình viên phát hiện sớm các side-effect không an toàn.

  • Lời giải: Sử dụng loading="lazy", định dạng WebP, và dùng các thư viện như react-optimized-image.

  • Lời giải: Viết CSS trực tiếp trong file JS, giúp scoped style (không bị ghi đè lẫn nhau) và dễ dàng thay đổi style dựa trên props.

  • Code Demo:

JavaScript
const Button = styled.button`
  background: ${props => props.primary ? "blue" : "gray"};
`;

  • Lời giải: Nếu danh sách bị đảo ngược hoặc thêm/xóa phần tử ở giữa, index sẽ thay đổi khiến React render sai hoặc giảm hiệu năng đáng kể.

  • Lời giải: React gom nhiều lệnh setCount, setFlag vào một lần render duy nhất ngay cả bên trong các hàm setTimeout hay Promise.

  • Lời giải: Là thuật toán mà React sử dụng để so sánh hai cây Virtual DOM nhằm xác định các phần cần được cập nhật.

  • Lời giải: (Trong Class Component) Tương đương với React.memo. Nó tự động thực hiện shallow comparison (so sánh nông) cho props và state.

  • Lời giải: Là bộ engine mới của React (từ bản 16) giúp phân mảnh các công việc render lớn thành các mảnh nhỏ để trình duyệt không bị treo (Concurrency).

  • Lời giải: Tái sử dụng (Reusability), Dễ bảo trì (Maintainability), Dễ kiểm thử (Testability).

  • Lời giải: React so sánh các phần tử trong mảng bằng Object.is(). Nếu có ít nhất một giá trị khác so với lần render trước, effect sẽ chạy lại.

  • Lời giải: Luôn cleanup các setInterval, addEventListener hoặc abort các request API trong hàm trả về của useEffect.

  • Lời giải: Để đánh dấu một cập nhật state là "độ ưu tiên thấp" (như search gợi ý), giúp UI chính (như gõ phím) không bị giật lag.

  • Lời giải: Thường chia theo: components/, hooks/, services/ (API), store/ (Redux), pages/, assets/, utils/.

Phản hồi từ học viên

5

Tổng 0 đánh giá
Developer Toolbox

TEXT CASE

FORMAT & CLEAN

ENCODE & DECODE

JSON & CRYPTO

Đã sao chép!!!
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.
Hotline: 0967025996
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.