🤖
Sẵn sàng thử sức?
Phỏng vấn thử với AI, nhận đánh giá và feedback chi tiết
Bắt đầu ngay →

Virtual DOM là gì? Tại sao React sử dụng Virtual DOM?

Virtual DOM là bản sao lightweight của Real DOM được lưu trong memory.

Cách hoạt động:

  1. State thay đổi → React tạo Virtual DOM mới
  2. So sánh (diff) Virtual DOM mới với cũ
  3. Chỉ update những phần thay đổi vào Real DOM

Tại sao? Thao tác Real DOM rất chậm (repaint, reflow). Virtual DOM giúp batch updates và tối ưu số lần thao tác DOM.

React Hooks: useState vs useReducer khi nào dùng?

useState: State đơn giản, logic update đơn giản.

useReducer: State phức tạp, nhiều sub-values, logic update phức tạp.

// useState - simple
const [count, setCount] = useState(0);

// useReducer - complex state
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment': return { ...state, count: state.count + 1 };
    case 'decrement': return { ...state, count: state.count - 1 };
    default: return state;
  }
};
const [state, dispatch] = useReducer(reducer, { count: 0 });

useCallback và useMemo khác nhau như thế nào?

useMemo: Cache giá trị tính toán (value).

useCallback: Cache function reference.

// useMemo - memorize computed value
const expensiveValue = useMemo(() => {
  return heavyComputation(a, b);
}, [a, b]);

// useCallback - memorize function
const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);

Khi nào dùng? Khi truyền callback cho child components đã được memo, hoặc khi computation expensive.

Giải thích React Component Lifecycle?

3 phases:

  1. Mounting: Component được tạo và insert vào DOM
  2. Updating: Props hoặc state thay đổi
  3. Unmounting: Component bị remove khỏi DOM
useEffect(() => {
  // Mounting + Updating
  console.log('Effect runs');
  
  return () => {
    // Cleanup (Unmounting)
    console.log('Cleanup');
  };
}, [dependency]);

Làm thế nào để tối ưu performance React app?

  • React.memo(): Prevent unnecessary re-renders
  • useMemo/useCallback: Cache values/functions
  • Code splitting: React.lazy() + Suspense
  • Virtualization: react-window cho long lists
  • Avoid inline objects/functions trong JSX
  • Key optimization: Stable keys trong lists
// Code splitting
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

// Virtualization
import { FixedSizeList } from 'react-window';
<FixedSizeList height={400} itemCount={10000} itemSize={35}>
  {Row}
</FixedSizeList>

Context API vs Redux - Khi nào dùng?

Context API:

  • State đơn giản, không update thường xuyên
  • Prop drilling nhẹ (theme, user, language)

Redux:

  • State phức tạp, nhiều components cần access
  • Cần middleware (async, logging)
  • Time-travel debugging
  • Predictable state management

Axios là gì? Tại sao dùng Axios thay vì fetch?

Axios là HTTP client phổ biến cho browser và Node.js.

Ưu điểm so với fetch:

  • Tự động transform JSON (không cần .json())
  • Request/Response interceptors
  • Timeout support built-in
  • Automatic XSRF protection
  • Cancel requests với AbortController hoặc CancelToken
  • Better error handling (reject 4xx/5xx)
// Fetch
const res = await fetch('/api/users');
if (!res.ok) throw new Error('Failed');
const data = await res.json();

// Axios - cleaner
const { data } = await axios.get('/api/users');

Axios Interceptors dùng để làm gì? Cho ví dụ?

Interceptors cho phép xử lý requests/responses trước khi chúng được gửi đi hoặc nhận về.

Use cases:

  • Add Authorization header tự động
  • Logging requests
  • Handle token refresh (401 errors)
  • Show/hide loading spinner
// Request interceptor - add token
axios.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  error => Promise.reject(error)
);

// Response interceptor - handle 401
axios.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401) {
      // Refresh token logic
      await refreshToken();
      return axios(error.config); // Retry
    }
    return Promise.reject(error);
  }
);

Cách tạo Axios instance và config mặc định?

Axios instance cho phép tạo client với base config riêng.

// api.js - Create instance
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.example.com/v1',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  }
});

// Usage
const users = await api.get('/users');
const user = await api.post('/users', { name: 'John' });

Best practice: Tạo file riêng cho API instance, export và import ở các components.

Cách cancel Axios request? Tại sao cần cancel?

Tại sao cần cancel?

  • User navigate ra trang khác
  • Search input - cancel request cũ khi user tiếp tục gõ
  • Prevent memory leaks trong React
// AbortController (modern)
const controller = new AbortController();

axios.get('/api/users', {
  signal: controller.signal
});

// Cancel
controller.abort();

// React useEffect cleanup
useEffect(() => {
  const controller = new AbortController();
  
  axios.get('/api/data', { signal: controller.signal })
    .then(res => setData(res.data))
    .catch(err => {
      if (axios.isCancel(err)) return; // Ignore
      console.error(err);
    });
  
  return () => controller.abort(); // Cleanup
}, []);

Axios Error Handling - Cách xử lý các loại error?

3 loại errors:

try {
  const response = await axios.get('/api/users');
} catch (error) {
  if (error.response) {
    // Server responded with 4xx/5xx
    console.log('Status:', error.response.status);
    console.log('Data:', error.response.data);
  } else if (error.request) {
    // No response received (network error)
    console.log('Network error:', error.request);
  } else {
    // Error setting up request
    console.log('Error:', error.message);
  }
}