JSX: phần mở rộng JavaScript và ví dụ sử dụng

Tác giả: IT Sectr Đã đăng: 2026-07-03 Thời gian đọc: 10 phút

JSX là phần mở rộng cú pháp giống XML dành cho JavaScript, được nhóm React phát triển để mô tả giao diện người dùng một cách khai báo. Không giống các công cụ template, JSX biên dịch thành các lời gọi hàm JavaScript thông thường, mang lại sức mạnh đầy đủ của ngôn ngữ trong đánh dấu. Theo React, 2024, JSX được hỗ trợ trong tất cả các framework và thư viện React hiện đại.

Các điểm chính

  • JSX là đường cú pháp trên React.createElement, cho phép viết đánh dấu giống HTML trong JavaScript.
  • Biểu thức trong JSX được nhúng qua dấu ngoặc nhọn — có thể sử dụng bất kỳ biểu thức JS nào.
  • Thuộc tính trong JSX được viết bằng camelCase (className, onClick, tabIndex), không phải kebab-case.
  • Biên dịch JSX sang JS được thực hiện bởi Babel, TypeScript hoặc esbuild trước khi thực thi trong trình duyệt.
  • Bảo vệ XSS được tích hợp sẵn — React thoát tất cả các giá trị trước khi kết xuất, ngăn chặn các cuộc tấn công chèn mã.

JSX là gì?

JSX (JavaScript XML) là phần mở rộng cú pháp cho JavaScript, được giới thiệu lần đầu trong React vào năm 2013. Nó cho phép nhà phát triển mô tả cấu trúc giao diện người dùng theo phong cách khai báo, kết hợp đánh dấu và logic trong một tập tin.

Trước JSX, các nhà phát triển sử dụng template chuỗi (Mustache, Handlebars) hoặc tạo phần tử DOM thủ công qua document.createElement. Cả hai cách tiếp cận đều có nhược điểm: template chuỗi không được kiểm tra kiểu, và tạo DOM thủ công rườm rà và dễ xảy ra lỗi.

React đã chọn một con đường khác — nhúng đánh dấu trực tiếp vào mã. Quyết định này đã gây ra tranh luận trong cộng đồng, nhưng theo thời gian nó đã trở thành tiêu chuẩn. Ngày nay, JSX không chỉ được sử dụng trong React mà còn trong SolidJS, Preact, Qwik và thậm chí trong Vue thông qua các plugin.

Cú pháp JSX cơ bản

Phần tử JSX trông giống thẻ HTML nhưng được nhúng trực tiếp vào JavaScript. Mỗi phần tử được biên dịch thành lời gọi React.createElement với ba đối số: loại phần tử, đối tượng props và các phần tử con. Một phần tử gốc là quy tắc bắt buộc: biểu thức JSX phải trả về một phần tử cha hoặc fragment.

js
import React from 'react';

// JSX cơ bản - một phần tử gốc
const element = (
  <div className="app">
    <h1>Hello, World!</h1>
    <p>Welcome to React</p>
  </div>
);

Fragment để nhóm

Khi không cần nút DOM bổ sung, hãy sử dụng React.Fragment hoặc cú pháp rút gọn <></>. Fragment không tạo phần tử DOM thật mà chỉ nhóm các nút con. Điều này đặc biệt hữu ích trong bảng và danh sách, nơi một wrapper bổ sung sẽ phá vỡ cấu trúc HTML.

js
function Columns() {
  return (
    <>
      <td>First</td>
      <td>Second</td>
    </>
  );
}

Biểu thức và biến trong JSX

Bất kỳ biểu thức JavaScript nào cũng được nhúng trong JSX qua dấu ngoặc nhọn { }. Bên trong, bạn có thể sử dụng biến, lời gọi hàm, toán tử ba ngôi và phương thức mảng. Kết xuất có điều kiện được thực hiện qua toán tử ba ngôi hoặc AND logic.

js
function Greeting({ name, isLoggedIn }) {
  const items = ['Red', 'Green', 'Blue'];

  return (
    <div>
      {/* Expression with variable */}
      <h1>Hello, {name}</h1>

      {/* Conditional rendering */}
      {isLoggedIn ?
        <p>Welcome back!</p :
        <button>Login</button>
      }

      {/* Render array */}
      <ul>
        {items.map(item =>
          <li key={item}>{item}</li>
        )}
      </ul>
    </div>
  );
}

Một giới hạn chính — chỉ có biểu thức mới có thể được sử dụng bên trong dấu ngoặc nhọn, không phải câu lệnh. Bạn không thể sử dụng if/else, for, switch — chỉ toán tử ba ngôi, toán tử logic và phương thức mảng. Lời gọi hàm được phép, bao gồm cả hàm mũi tên.

Sự khác biệt giữa JSX và HTML

JSX trông giống HTML nhưng có những khác biệt cơ bản. Thuộc tính được viết bằng camelCase — className thay vì class, onClick thay vì onclick, tabIndex thay vì tabindex. Điều này là do JSX biên dịch thành JavaScript, nơi dấu gạch nối trong tên thuộc tính không được phép.

HTMLJSXLý do
class="wrapper"className="wrapper"class là từ khóa dành riêng trong JS
onclick="handle()"onClick={handle}camelCase cho thuộc tính JS
style="color: red"style={{ color: ‘red’ }}Đối tượng style thay vì chuỗi
<input disabled><input disabled={true}>Thuộc tính boolean tường minh

Một khác biệt quan trọng nữa — thẻ tự đóng. Trong HTML, một số thẻ (br, hr, input) có thể không đóng. Trong JSX, tất cả các thẻ tự đóng phải có dấu gạch chéo đóng: <br />, <input />. Tên thuộc tính SVG cũng được chuyển thành camelCase: strokeWidth, fillOpacity.

Cách JSX được biên dịch thành JavaScript

Trình duyệt không hiểu JSX trực tiếp. Trước khi thực thi, mã JSX đi qua một trình biên dịch — Babel, TypeScript hoặc esbuild. Mỗi phần tử JSX được biến thành lời gọi createElement hoặc jsx/runtime.

Chuyển đổi qua Babel

js
// JSX gốc
const element = <h1 className="title">Hello</h1>;

// Sau khi biên dịch
const element = React.createElement(
  'h1',
  { className: 'title' },
  'Hello'
);

Với React 17, một phép biến đổi JSX mới đã xuất hiện không yêu cầu import React. Import tự động jsx-runtime cho phép viết component mà không cần import React from ‘react’. Babel và TypeScript hỗ trợ phép biến đổi này thông qua cấu hình {"runtime": "automatic"}.

JSX ngoài React: Solid, Preact, Vue

Mặc dù JSX gắn liền với React, các framework khác cũng sử dụng nó. SolidJS sử dụng JSX với biên dịch thành các nút DOM thật, không cần Virtual DOM. Preact là một thay thế nhẹ cho React với hỗ trợ JSX đầy đủ. Vue hỗ trợ JSX qua @vue/babel-plugin-jsx, mặc dù template chính của nó là template.

Một khác biệt chính là ngữ nghĩa biểu thức. Trong React, các biểu thức JSX được thực thi ở mỗi lần kết xuất. Trong SolidJS, JSX biên dịch một lần và các bản cập nhật được theo dõi qua tín hiệu. Điều này ảnh hưởng đến hiệu suất: SolidJS không cần Virtual DOM và điều phối, làm cho việc kết xuất JSX nhanh hơn.

Trong TypeScript, JSX được hỗ trợ ở cấp độ ngôn ngữ. Các tập tin có phần mở rộng .tsx tự động xử lý cú pháp JSX. Đánh kiểu props là một trong những lợi thế chính của TypeScript + JSX: IDE gợi ý các thuộc tính mong đợi, kiểu callback và tính bắt buộc của props.

Thực hành tốt nhất với JSX

Viết mã JSX dễ đọc và dễ bảo trì. Trích xuất các biểu thức phức tạp vào các biến hoặc hàm riêng — điều này cải thiện khả năng đọc và cho phép kiểm tra logic riêng biệt với đánh dấu. Sử dụng fragment thay vì các wrapper div không cần thiết.

Quy tắc thụt lề — duy trì thụt lề cho các phần tử lồng nhau. Mỗi cấp độ lồng nhau là một cấp độ thụt lề. Thẻ đóng phải ở cùng cấp với thẻ mở. Đối với các thuộc tính dài, hãy sử dụng xuống dòng.

Tránh hàm mũi tên nội tuyến trong props nếu chúng được tạo ra ở mỗi lần kết xuất. Trong trường hợp này, hãy bọc callback trong useCallback hoặc di chuyển hàm ra ngoài component. Chia các component phức tạp thành những component nhỏ hơn — mỗi component nên xử lý một đơn vị logic của giao diện.

Câu hỏi thường gặp

Có thể sử dụng JSX mà không cần React không?

Có, thông qua plugin Babel @babel/plugin-transform-react-jsx, JSX có thể được cấu hình cho bất kỳ thư viện nào. SolidJS, Preact, Nerv và các framework khác sử dụng JSX với runtime riêng. Để hoàn toàn độc lập, bạn có thể đặt pragma thành hàm của riêng mình.

Tại sao không thể dùng class thay vì className trong JSX?

class là từ khóa dành riêng trong JavaScript. JSX biên dịch thành createElement, nơi đối số thứ hai truyền đối tượng props. Thuộc tính class xung đột với cú pháp lớp ES6, vì vậy React đã chọn className.

Làm thế nào để thêm nhiều class trong JSX?

Sử dụng template string hoặc thư viện classnames: className={`btn ${isActive ? ‘active’ : ‘’}`}. Đối với logic phức tạp, hãy cài đặt gói npm clsx hoặc classnames, chấp nhận cả đối tượng và mảng.

JSX có hỗ trợ cấu trúc điều kiện không?

JSX chỉ hỗ trợ biểu thức, không phải câu lệnh. Đối với điều kiện, hãy sử dụng toán tử ba ngôi, AND logic (&&) hoặc OR logic (||). Đối với logic phức tạp, hãy trích xuất điều kiện vào một biến hoặc hàm riêng.

Tại sao cần key cho danh sách trong JSX?

Thuộc tính key giúp React xác định các phần tử danh sách khi kết xuất lại. Không có key, React kết xuất lại toàn bộ danh sách khi có thay đổi. Với key duy nhất, React tái sử dụng các nút DOM và sắp xếp lại các phần tử thay vì tạo lại chúng.

Tổng kết

  • JSX là phần mở rộng JavaScript giống XML để mô tả UI một cách khai báo, thay thế cho template chuỗi.
  • Dấu ngoặc nhọn cho phép nhúng bất kỳ biểu thức JS nào — biến, hàm, toán tử ba ngôi.
  • Thuộc tính trong JSX được viết bằng camelCase, style được truyền dưới dạng đối tượng, thuộc tính boolean rõ ràng.
  • Biên dịch JSX thành createElement được thực hiện tự động bởi Babel hoặc TypeScript.
  • Một phần tử gốc hoặc fragment là bắt buộc cho mỗi biểu thức JSX.
  • JSX ngoài React — SolidJS, Preact, Vue và Qwik cũng hỗ trợ JSX thông qua runtime riêng.
  • TypeScript với phần mở rộng .tsx cung cấp đánh kiểu đầy đủ cho props và thuộc tính JSX.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm