Mục lục

Thinking in React: Tư duy theo React

Chuyển đổi từ tư duy Mệnh lệnh (Imperative) sang Khai báo (Declarative). Quy tắc State vs Props, Luồng dữ liệu một chiều và cách thiết kế Component chuẩn Senior.

React không chỉ là một thư viện, nó là một cách tư duy để xây dựng giao diện người dùng dựa trên Component.

1. Declarative vs Imperative (Khai báo vs Mệnh lệnh)

Đây là sự thay đổi tư duy lớn nhất khi chuyển từ JavaScript thuần (jQuery) sang React.

  • Mệnh lệnh (Imperative - HOW): Bạn chỉ dẫn trình duyệt từng bước để thay đổi giao diện. (Ví dụ: Tìm nút, thêm class, thay đổi text).
  • Khai báo (Declarative - WHAT): Bạn mô tả giao diện trông như thế nào tương ứng với một trạng thái (State). React sẽ tự lo phần "làm sao để cập nhật DOM".
tsx:
// ❌ Cách tiếp cận Mệnh lệnh (jQuery style)
const btn = document.querySelector('#toggle');
btn.addEventListener('click', () => {
  if (btn.classList.contains('active')) {
    btn.classList.remove('active');
    btn.innerText = 'OFF';
  } else {
    btn.classList.add('active');
    btn.innerText = 'ON';
  }
});

// ✅ Cách tiếp cận Khai báo (React style)
function Toggle() {
  const [isActive, setIsActive] = useState(false);

  return (
    <button onClick={() => setIsActive(!isActive)}>
      {isActive ? 'ON' : 'OFF'}
    </button>
  );
}

2. State vs Props: Phân biệt rõ ràng

Một Senior React Dev luôn biết khi nào dùng State, khi nào dùng Props.

Tiêu chíProps (Thuộc tính)State (Trạng thái)
Bản chấtDữ liệu truyền từ Cha xuống Con.Dữ liệu nội bộ của Component.
Thay đổiRead-only (Immutable).Có thể thay đổi (Mutable via setter).
Sở hữuComponent Cha sở hữu.Bản thân Component sở hữu.

Quy tắc vàng: Nếu dữ liệu có thể được tính toán từ Props hoặc một State khác, đừng tạo State mới. Hãy dùng dữ liệu dẫn xuất (Derived Data).

3. Unidirectional Data Flow (Luồng dữ liệu một chiều)

Trong React, dữ liệu luôn chảy xuống (Downwards) từ Cha đến Con thông qua Props.

  • Nếu Con muốn thay đổi dữ liệu của Cha?
  • Giải pháp: Cha truyền một Callback Function xuống cho Con. Con gọi function đó để "báo cáo" lên Cha.
tsx:
function Parent() {
  const [count, setCount] = useState(0);
  return <Child onIncrement={() => setCount(count + 1)} />;
}

function Child({ onIncrement }) {
  return <button onClick={onIncrement}>Tăng</button>;
}

4. Quy trình thiết kế Component chuẩn

Khi nhận bản design, đừng bắt tay vào code ngay. Hãy làm theo 5 bước:

  1. Chia nhỏ UI thành cây Component: Xác định ranh giới giữa các khối (Header, Sidebar, SearchBar, ProductTable).
  2. Xây dựng phiên bản tĩnh (Static): Viết JSX và truyền Props cứng, chưa cần State.
  3. Xác định trạng thái tối thiểu (Minimal State): Chỉ giữ những gì thực sự thay đổi. Tránh dư thừa.
  4. Xác định nơi đặt State (Lifting State Up): Tìm Component cha chung gần nhất của tất cả các component cần state đó.
  5. Thêm luồng dữ liệu ngược: Truyền các hàm setter xuống con để cập nhật state.

5. Composition over Inheritance (Lồng ghép trên Kế thừa)

React khuyến khích việc kết hợp các component nhỏ lại với nhau (Composition) thay vì tạo ra một chuỗi kế thừa phức tạp như trong lập trình hướng đối tượng (OOP).

tsx:
function Dialog({ children }) {
  return <div className="modal">{children}</div>;
}

function WelcomeDialog() {
  return (
    <Dialog>
      <h1>Chào mừng!</h1>
      <p>Cảm ơn bạn đã tham gia hệ thống.</p>
    </Dialog>
  );
}

Kết luận

Tư duy theo React là tư duy theo ComponentState. Nếu bạn thấy mình đang cố gắng "chạm" vào DOM hoặc code trở nên quá phức tạp để theo dõi luồng dữ liệu, hãy quay lại bước 1: Thinking in React.

Quảng cáo
mdhorizontal