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 4 – React Hooks – State: Hooks, useState và useEffect

Series 4 – React Hooks – State   Bài 1 : Hooks, useState và useEffect – Quản lý dữ liệu và side effects trong React 1. React Hooks là gì? Hooks là những hàm do React cung cấp để Function Component sử dụng các khả năng như quản lý state, đồng bộ với hệ thống bên […]

Series 4 – React Fundamentals: List Rendering, Forms, Form Handling

Series 4 – React Fundamentals   Bài 3: List Rendering, Forms và Form Handling – Hiển thị danh sách và xử lý biểu mẫu trong React   1. Mở đầu Trong một ứng dụng thực tế, dữ liệu thường được hiển thị dưới dạng danh sách: danh sách sản phẩm, bài viết, người dùng hoặc công việc […]

Series 4 – React Fundamentals:  State, Events và Conditional Rendering

Series 4 – React Fundamentals   Bài 2: State, Events và Conditional Rendering – Cách React xử lý tương tác người dùng 1. Mở đầu Một giao diện website không chỉ hiển thị nội dung cố định. Khi người dùng nhấn nút, nhập dữ liệu, đăng nhập hoặc thêm sản phẩm vào giỏ hàng, giao diện cần […]

Series 3 – JavaScript Fundamentals: Async → API

Series 3 — JavaScript Fundamentals   JavaScript → DOM → Async → API   Bài 2. Asynchronous JavaScript & API – Xử lý bất đồng bộ và giao tiếp với Server 1. Vì sao cần Asynchronous JavaScript? Trong các website hiện đại, nhiều thao tác cần thời gian để hoàn thành, chẳng hạn như gọi API lấy […]

Transactions & ACID

1. Transaction là gì? Transaction (giao dịch) là một nhóm thao tác trên database được xem như một đơn vị xử lý logic. Mục tiêu là bảo đảm những thay đổi liên quan được thực hiện theo cách nhất quán: nếu giao dịch thành công thì các thay đổi cần thiết được xác nhận; nếu […]

Database Normalization – 1NF, 2NF, 3NF & Denormalization

1. Database Normalization là gì? Database Normalization (chuẩn hóa dữ liệu) là quá trình tổ chức dữ liệu thành các bảng và quan hệ hợp lý nhằm giảm dư thừa không cần thiết, tránh dữ liệu mâu thuẫn và duy trì tính toàn vẹn của database. Khi thiết kế database, nếu lưu tất cả thông […]

Leave a Reply

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