MERN (6) - JSX và Babel

Bài trước: MERN (5) - Tổng quan React và component
-----


1.6.4       JSX và Babel


JSX là viết tắt của JavaScript XML, là một loại cú pháp mở rộng dành cho ngôn ngữ JavaScript viết theo kiểu XML.

Vậy JSX = JavaScript + XML.

Nhờ có JSX, lập trình viên có thể lập trình với React bằng cú pháp của XML thay vì cú pháp của JavaScript.

Cụ thể, thay vì viết hàm React.createElement() để tạo ra một phần tử DOM bằng JavaScript thì có thể viết bằng cú pháp của XML.

Nhưng trình duyệt thì lại chỉ làm việc được với JavaScript, nên phải “dịch” lại đoạn mã JSX ra mã JavaScript, để làm việc này cần dùng tới công cụ (thư viện) Babel.

Để rõ hơn các ý ở trên, cùng quan sát một số ví dụ sau đây.

Trở lại ví dụ trước, trong tập tin [like_button.js], có khai báo một biến để tham chiếu tới hàm “tạo một phần tử HTML” của React có tên là createElement.

const e = React.createElement;

Sau đó gọi hàm createElement thông qua biến “e” để tạo nút Like, với ba tham số truyền vào:

return e(
      'button',
      { onClick: () => this.setState({ liked: true }},
      'Like'
    );

Hiểu nôm na, hàm trên sẽ tạo một nút có kiểu là “button”, gắn một hàm xử lý sự kiện bấm chuột (onClick) cho nút này, nút có tên là “Like”.

Xem định nghĩa của hàm React.createElement tại đây: 

function createElement(type, config, children) {}

Ngoài việc tạo nút Like bằng cách gọi hàm của React viết bằng JavaScript như trên, cũng có thể tạo nút Like bằng cú pháp JSX (hay XML) như sau:

// tạo nút Like theo cú pháp JSX
return (
  <button onClick={() => this.setState({ liked: true })}>
    Like
  </button>
);

Tạo nút Like có sử dụng JSX và Babel

Phần này sẽ hướng dẫn từng bước để tạo một nút Like bằng JSX và Babel, tuy nhiên đây chỉ là ví dụ minh họa để hiểu cách làm việc của JSX và Babel, trong các dự án thực tế không làm theo cách này, vì nó làm ứng dụng chạy rất chậm.

– Trong tập tin component.html, tạo một phần tử HTML để chứa nút Like (tạo container)

<div id="like_button_container"></div>

– Trong tập tin like_button.js, tạo nút Like bằng cú pháp JSX, đoạn mã sau trả về một React element

 <button onClick={() => this.setState({ liked: true })}>
    Like
  </button>

– Gọi hàm render() của ReactDOM để chuyển một React element thành một nút trong cây DOM (xuất nút Like lên trang HTML), hàm render() cần truyền vào hai tham số: một là React element, hai là container (nút Like sẽ được xuất ở đâu trên trang HTML).

ReactDOM.render(
  <button onClick={() => this.setState({ liked: true })}>
    Like
  </button>,
  document.getElementById('like_button_container')
);

– Gọi thư viện Babel để biên dịch mã JSX thành mã JavaScript (thực tế là dịch ra hàm React.createElement)

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

– Biên dịch mã JSX thành JavaScript bằng thư viện Babel

<script type="text/babel" src="like_button.js"></script>

Đoạn mã đầy đủ:

[component.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- hiển thị một nút like ở đây -->
    <div id="like_button_container"></div>

    <!-- tải React từ trên mạng về trình duyệt -->
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <!-- Gọi thư viện Babel để biên dịch mã JSX -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <!-- tải đoạn mã tạo nút Like bằng JSX -->
    <script type="text/babel" src="like_button.js"></script>
</body>
</html>

[like_button.js]

ReactDOM.render(
  <button onClick={() => this.setState({ liked: true })}>
    Like
  </button>,
  document.getElementById('like_button_container')
);

– Mở tập tin component.html bằng giao thức http để xem kết quả (chạy bằng giao thức file sẽ bị lỗi liên quan đến XMLHttpRequest)


– Nút Like sẽ xuất hiện trên cửa sổ trình duyệt.

Tham khảo thêm việc chuyển mã từ JSX sang JavaScript (cụ thể là chuyển đoạn mã tạo một phần tử HTML từ JSX sang hàm React.createElement) tại trang web này.


1.6.5       JSX preprocessor


Như đã trình bày ở phần trên, việc tải thư viện Babel về trình duyệt, sau đó dùng Babel để chuyển mã JSX sang hàm React.createElemment sẽ làm cho ứng dụng chạy chậm. Vậy có cách nào để khắc phục điều này không. Giải pháp là chuyển đổi JSX sang hàm React.createElement ngay lúc lập trình.
JSX preprocessor là chương trình giúp chuyển đổi mã JSX sang hàm React.createElement ngay lúc lập trình. Phần sau sẽ hướng dẫn cách cài đặt và chạy chương trình JSX preprocessor.

Cài đặt JSX preprocessor vào dự án

– Tạo thư mục dự án, ví dụ jsxpreprocessor

– Mở chương trình cửa sổ dòng lệnh (cmd), di chuyển tới thư mục jsxpreprocessor, nhập dòng lệnh sau, mục đích là dùng npm để tạo ra tập tin package.json nhằm quản lý các package.

npm init –y

Ví dụ:

D:\Liv\TuHoc\IT\ChuyenNganh\CNPM\MERN\codes\react\jsxpreprocessor>npm init -y
Wrote to D:\Liv\TuHoc\IT\ChuyenNganh\CNPM\MERN\codes\react\jsxpreprocessor\package.json:
{
  "name": "jsxpreprocessor",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

– Dùng npm để cài hai chương trình (gói, hay package) babel-clibabel-preset-react-app vào dự án
Chương trình babel-cli dùng để chạy lệnh babel trên cửa sổ dòng lệnh, đọc thêm về babel-cli ở đây (https://babeljs.io/docs/en/babel-cli)

Chương trình babel-preset-react-app là bộ quy tắc định sẵn (preset) dùng để chuyển JSX thành JavaScript

Tại cửa sổ dòng lệnh, gõ tiếp lệnh sau,

npm install babel-cli@6 babel-preset-react-app@3

Ví dụ,

D:\Liv\TuHoc\IT\ChuyenNganh\CNPM\MERN\codes\react\jsxpreprocessor>npm install babel-cli@6 babel-preset-react-app@3
+ babel-cli@6.26.0
+ babel-preset-react-app@3.1.2
added 308 packages from 135 contributors and audited 3622 packages in 41.521s

Quá trình cài đặt trên sẽ cập nhật thông tin trong tập tin package.json, tạo thêm tập tin package-lock.json, tạo thêm thư mục node_modules cùng nội dung bên trong.

– Chạy JSX preprocessor

Trong dự án, tạo thêm thư mục src, trong cửa sổ dòng lệnh, chạy tiếp lệnh sau,

npx babel --watch src --out-dir . --presets react-app/prod

Ví dụ,

D:\Liv\TuHoc\IT\ChuyenNganh\CNPM\MERN\codes\react\jsxpreprocessor>npx babel --watch src --out-dir . --presets react-app/prod

Sẽ tìm hiểu về lệnh npx ở phần sau. Chỉ cần biết là lệnh npx sẽ khởi chạy chương trình tiền xử lý JSX (JSX preprocessor) để chuyển tập tin mã nguồn dạng JSX về dạng JavaScript, cửa sổ dòng lệnh sẽ luôn ở trạng thái chờ.

Trong thư mục src, bạn thử tạo tập tin like_button.js với nội dung sau (viết mã dạng JSX):

[src/like_button.js]

ReactDOM.render(
  <button onClick={() => this.setState({ liked: true })}>
    Like
  </button>,
  document.getElementById('like_button_container')
);

JSX preprocessor sẽ tự động tạo ra tập tin like_button.js trong thư mục jsxpreprocessor với mã nguồn dạng JavaScript. Trình duyệt đã có thể dịch và thực thi được đoạn mã JavaScript này mà không cần phải dùng tới thư viện Babel. Nếu bạn chỉnh sửa tập tin trong [src/like_button.js], nội dung trong [jsxpreprocessor/ like_button.js] cũng sẽ được cập nhật.
[jsxpreprocessor/ like_button.js]

var _this = this;

ReactDOM.render(React.createElement(
  'button',
  { onClick: function onClick() {
      return _this.setState({ liked: true });
    } },
  'Like'

), document.getElementById('like_button_container'));
-----
Cập nhật: [27/04/2020]
-----
Xem thêm: MERN (7) - Chương trình React đầu tiên
Xem thêm: Danh sách bài học