Series 4 – React Fundamentals

 

Bài 1:JSX, Components và Props – Ba nền tảng đầu tiên khi học React

1. Mở đầu

Khi xây dựng một website bằng HTML, CSS và JavaScript, chúng ta thường tạo cấu trúc giao diện bằng HTML, sau đó sử dụng JavaScript để xử lý dữ liệu và tương tác.

Tuy nhiên, khi website có nhiều khu vực như Header, Sidebar, Product List và Footer, việc quản lý toàn bộ giao diện trong một file có thể khiến code khó đọc và khó bảo trì.

React giải quyết vấn đề này bằng cách tổ chức giao diện thành những thành phần nhỏ có thể tái sử dụng. Để bắt đầu làm việc với React, chúng ta cần hiểu ba khái niệm nền tảng: JSX, Components và Props.

2. JSX là gì?

JSX là cú pháp mở rộng của JavaScript, cho phép lập trình viên mô tả giao diện theo cách gần giống HTML ngay trong code JavaScript.

Ví dụ, với HTML thông thường:

<h1>Xin chào Khoa!</h1>
<p>Chào mừng bạn đến với website.</p>

Trong React, chúng ta có thể viết:

const element = (
    <div>
        <h1>Xin chào Khoa!</h1>
        <p>Chào mừng bạn đến với website.</p>
    </div>
);

Đoạn code trên sử dụng JSX để mô tả một phần giao diện. JSX không phải HTML nguyên bản; công cụ build sẽ chuyển đổi cú pháp này thành JavaScript mà React có thể xử lý.

2.1. Sử dụng JavaScript trong JSX

Một trong những ưu điểm của JSX là có thể hiển thị dữ liệu từ biến và biểu thức JavaScript bằng cặp dấu ngoặc nhọn {}.

function Welcome() {
    const name = "Khoa";
    const age = 21;

    return (
        <div>
            <h1>Xin chào, {name}!</h1>
            <p>Bạn {age} tuổi.</p>
            <p>Năm sau bạn sẽ {age + 1} tuổi.</p>
        </div>
    );
}

Khi Component được render, React sẽ hiển thị giá trị của name, age và biểu thức age + 1.

Lưu ý rằng {} trong JSX dùng để nhúng biểu thức JavaScript, không phải để viết trực tiếp mọi câu lệnh. Chẳng hạn, bạn không thể đặt một câu lệnh if thông thường trực tiếp vào vị trí biểu thức JSX.

2.2. Một số quy tắc quan trọng của JSX

Quy tắc 1: Phải có một phần tử gốc hoặc sử dụng Fragment.

function App() {
    return (
        <>
            <h1>Trang chủ</h1>
            <p>Đây là website của tôi.</p>
        </>
    );
}

Fragment <>...</> giúp nhóm nhiều phần tử mà không cần tạo thêm một phần tử DOM bao quanh.

Quy tắc 2: Sử dụng className thay cho class.

<div className="container">Hello React</div>

Quy tắc 3: Đóng thẻ đúng cách.

<img src="/avatar.png" alt="Avatar" />
<input type="text" />

Quy tắc 4: Sử dụng tên thuộc tính phù hợp với JSX.

Ví dụ, htmlFor được dùng thay cho for trong thẻ label.

<label htmlFor="email">Email</label>
<input id="email" type="email" />

Những quy tắc này giúp bạn tránh nhiều lỗi cú pháp khi bắt đầu viết giao diện React.

3. Components là gì?

Component là một đơn vị giao diện độc lập có thể được tái sử dụng trong ứng dụng React.

Thay vì viết toàn bộ giao diện trong một khối code lớn, chúng ta có thể chia nó thành các Component nhỏ.

Ví dụ, một website bán hàng có thể được tổ chức như sau:

App
├── Header
├── ProductList
│   ├── ProductCard
│   ├── ProductCard
│   └── ProductCard
└── Footer

Mỗi Component đảm nhận một nhiệm vụ cụ thể. Header hiển thị phần đầu trang, ProductList quản lý khu vực danh sách sản phẩm, còn ProductCard mô tả giao diện của một sản phẩm.

3.1. Cách tạo một Component

Trong React hiện đại, Function Component là cách viết phổ biến.

function Header() {
    return (
        <header>
            <h1>My Shop</h1>
            <nav>
                <a href="/">Trang chủ</a>
                <a href="/products">Sản phẩm</a>
            </nav>
        </header>
    );
}

export default Header;

Trong ví dụ trên:

  • Header là tên Component.
  • Hàm Header() trả về JSX mô tả giao diện.
  • export default Header cho phép file khác import Component này làm export mặc định.

Tên Component cần bắt đầu bằng chữ cái viết hoa để React phân biệt Component với các thẻ HTML như header, div hay p.

3.2. Sử dụng Component

Giả sử file Header.jsx chứa Component Header, bạn có thể sử dụng nó trong App.jsx:

import Header from "./Header";

function App() {
    return (
        <div>
            <Header />
            <main>
                <h2>Chào mừng đến với My Shop</h2>
            </main>
        </div>
    );
}

export default App;

Cú pháp <Header /> cho phép sử dụng Component như một phần của giao diện.

Điều này giúp chúng ta tái sử dụng cùng một Component ở nhiều vị trí thay vì sao chép toàn bộ phần code giao diện.

3.3. Nguyên tắc chia Component

Không phải cứ mỗi thẻ HTML là cần tạo một Component riêng. Việc chia Component nên dựa trên chức năng, khả năng tái sử dụng và độ phức tạp của giao diện.

Một số nguyên tắc hữu ích:

  • Mỗi Component nên có nhiệm vụ tương đối rõ ràng.
  • Những phần giao diện lặp lại có thể được tách thành Component dùng chung.
  • Tránh tạo quá nhiều Component nhỏ nếu chúng không mang lại lợi ích về tổ chức code.
  • Đặt tên Component thể hiện đúng chức năng của nó.

4. Props là gì?

Props là viết tắt của Properties, dùng để truyền dữ liệu từ Component cha xuống Component con.

Hãy tưởng tượng một danh sách sản phẩm có nhiều sản phẩm khác nhau. Nếu mỗi ProductCard đều viết cố định tên, giá và hình ảnh, chúng ta sẽ phải sao chép code nhiều lần.

Props giúp giải quyết vấn đề đó bằng cách cho phép một Component nhận dữ liệu khác nhau mỗi khi được sử dụng.

4.1. Truyền Props vào Component

Ví dụ:

function ProductCard(props) {
    return (
        <div className="product-card">
            <h2>{props.name}</h2>
            <p>Giá: {props.price} VNĐ</p>
        </div>
    );
}

function App() {
    return (
        <div>
            <ProductCard name="Bàn phím" price={500000} />
            <ProductCard name="Chuột máy tính" price={250000} />
        </div>
    );
}

Ở đây, App là Component cha, còn ProductCard là Component con.

Khi truyền:

<ProductCard name="Bàn phím" price={500000} />

React cung cấp các giá trị name và price cho Component thông qua đối tượng props.

Kết quả là hai sản phẩm có tên và giá khác nhau nhưng sử dụng chung một cấu trúc giao diện.

4.2. Sử dụng Destructuring với Props

Thay vì viết props.name và props.price nhiều lần, chúng ta có thể sử dụng Destructuring:

function ProductCard({ name, price }) {
    return (
        <div className="product-card">
            <h2>{name}</h2>
            <p>Giá: {price} VNĐ</p>
        </div>
    );
}

Cách viết này ngắn gọn hơn và thường được sử dụng trong các dự án React.

4.3. Truyền nhiều loại dữ liệu qua Props

Props không chỉ dùng để truyền chuỗi. Bạn có thể truyền số, boolean, mảng, object hoặc hàm.

function UserCard({ user, isOnline, onViewProfile }) {
    return (
        <div>
            <h2>{user.name}</h2>
            <p>{isOnline ? "Đang trực tuyến" : "Ngoại tuyến"}</p>

            <button onClick={onViewProfile}>
                Xem hồ sơ
            </button>
        </div>
    );
}

function App() {
    const user = {
        name: "Khoa",
        age: 21,
    };

    function handleViewProfile() {
        console.log("Mở hồ sơ người dùng");
    }

    return (
        <UserCard
            user={user}
            isOnline={true}
            onViewProfile={handleViewProfile}
        />
    );
}

Trong ví dụ trên:

  • user là object chứa dữ liệu người dùng.
  • isOnline là boolean xác định trạng thái trực tuyến.
  • onViewProfile là hàm được truyền từ Component cha xuống Component con.

Điều này giúp Component con có thể hiển thị dữ liệu và gọi hành vi do Component cha cung cấp.

4.4. Props có thể bị thay đổi trực tiếp không?

Props nên được xem là dữ liệu chỉ đọc bên trong Component nhận chúng.

Ví dụ không nên làm:

function ProductCard({ price }) {
    price = price - 10000;

    return <p>{price}</p>;
}

Thay vì thay đổi Props, hãy để Component cha quyết định dữ liệu cần truyền xuống hoặc sử dụng State nếu Component thực sự cần quản lý dữ liệu có thể thay đổi.

Đặc biệt, không nên sửa trực tiếp object hoặc mảng nhận qua Props. Việc thay đổi dữ liệu dùng chung có thể dẫn đến những lỗi khó theo dõi.

5. Kết hợp JSX, Components và Props

Ba khái niệm này có mối quan hệ chặt chẽ:

  • JSX mô tả cấu trúc giao diện.
  • Components chia giao diện thành các phần độc lập và có thể tái sử dụng.
  • Props truyền dữ liệu từ Component cha xuống Component con.

Ví dụ tổng hợp:

function ProductCard({ name, price, inStock }) {
    return (
        <article className="product-card">
            <h2>{name}</h2>
            <p>Giá: {price.toLocaleString("vi-VN")} VNĐ</p>
            <p>{inStock ? "Còn hàng" : "Hết hàng"}</p>
        </article>
    );
}

function App() {
    const products = [
        { id: 1, name: "Bàn phím", price: 500000, inStock: true },
        { id: 2, name: "Chuột", price: 250000, inStock: false },
    ];

    return (
        <main>
            <h1>Danh sách sản phẩm</h1>

            {products.map((product) => (
                <ProductCard
                    key={product.id}
                    name={product.name}
                    price={product.price}
                    inStock={product.inStock}
                />
            ))}
        </main>
    );
}

export default App;

Ví dụ này sử dụng JSX để mô tả giao diện, Component ProductCard để tái sử dụng cấu trúc sản phẩm và Props để truyền dữ liệu cho từng sản phẩm.

Thuộc tính key giúp React nhận diện các phần tử trong danh sách. Đây là chủ đề sẽ được tìm hiểu kỹ hơn khi học List Rendering.

6. Bài tập thực hành

Hãy xây dựng giao diện danh sách nhân viên bằng React.

Yêu cầu:

  1. Tạo Component EmployeeCard.
  2. Sử dụng Props để truyền tên, chức vụ và mức lương.
  3. Hiển thị thông tin bằng JSX.
  4. Tạo ít nhất ba nhân viên với dữ liệu khác nhau.
  5. Tách Component ra file riêng và import vào App.jsx.
  6. Thêm một Props boolean để hiển thị trạng thái đang làm việc hoặc đã nghỉ việc.

Bạn có thể mở rộng bài tập bằng cách bổ sung ảnh đại diện và một hàm xử lý khi nhấn nút xem chi tiết nhân viên.

7. Kết luận

JSX, Components và Props là ba nền tảng quan trọng khi bắt đầu học React. JSX giúp mô tả giao diện, Components giúp tổ chức và tái sử dụng code, còn Props cho phép truyền dữ liệu giữa các thành phần.

Khi hiểu rõ cách ba khái niệm này phối hợp với nhau, bạn sẽ dễ dàng chuyển từ những giao diện đơn giản sang các ứng dụng có cấu trúc rõ ràng hơn.

Bài tiếp theo: State, Events và Conditional Rendering – Quản lý trạng thái, xử lý tương tác và cập nhật giao diện trong React.

Bài viết khác

Series 7 — Web Quality – Engineering :Testing – Unit Testing, Integration Testing, Web Performance – Core Web Vitals, Code Splitting, Lazy Loading

Series 7 — Web Quality – Engineering Bài 3: Testing – Unit Testing, Integration Testing và End-to-End Testing trong ứng dụng web 1. Vì sao ứng dụng web cần Testing? Trong quá trình phát triển Frontend, chúng ta thường kiểm tra ứng dụng bằng cách chạy website trên trình duyệt, nhấn vào các nút, nhập […]

Series 7 — Web Quality – Engineering : Authentication & Authorization

Series 7 — Web Quality – Engineering Bài 1: Authentication & Authorization – Xác thực và phân quyền trong ứng dụng web 1. Mở đầu Khi xây dựng một ứng dụng web có chức năng đăng nhập, chúng ta thường nghĩ rằng chỉ cần tạo biểu mẫu nhập email, mật khẩu và kiểm tra thông […]

Series 6 – Next.js Advanced – Production: Next.js Build & Deployment

Series 6 – Next.js Advanced & Production Bài 5: Next.js Build & Deployment – Từ mã nguồn đến môi trường Production 1. Mở đầu Trong quá trình phát triển một ứng dụng web, việc chạy thành công trên máy tính cá nhân chưa có nghĩa là ứng dụng đã sẵn sàng để đưa đến người […]

Series 6 – Next.js Advanced – Production: Next.js Internationalized Routing Next.js Static Export

Series 6 – Next.js Advanced & Production   Bài 3: Next.js Internationalized Routing – Tổ chức URL cho website đa ngôn ngữ 1. Mở đầu Sau khi xây dựng cơ chế dịch nội dung và định dạng theo locale, ứng dụng cần một cách để người dùng truy cập đúng phiên bản ngôn ngữ. Ví […]

Series 6 – Next.js Advanced & Production: Metadata & SEO, Internationalization (i18n) & Localization (l10n)

Series 6 – Next.js Advanced & Production Bài 1: Metadata & SEO trong Next.js – Tối ưu thông tin và khả năng hiển thị trên công cụ tìm kiếm 1. Mở đầu Khi xây dựng một website, việc hoàn thiện giao diện và chức năng mới chỉ là một phần của quá trình phát triển. […]

Series 5 – Next.js Fundamentals: CSR, SSR, SSG, ISR và cách lựa chọn

Series 5 – Next.js Fundamentals   Bài 7 : CSR, SSR, SSG và ISR – Các chiến lược Rendering trong Next.js 1. Mở đầu Khi xây dựng một website bằng React, chúng ta thường tập trung vào việc tạo component, quản lý state và hiển thị giao diện trên trình duyệt. Tuy nhiên, khi ứng dụng […]

Leave a Reply

Your email address will not be published. Required fields are marked *