Những chuỗi ngày cận Tết, quây quần bên gia đình, bên nồi bánh xanh đỏ lửa, nghi ngút khói mà thấy hạnh phúc vô cùng. Lại còn hì hục nướng củ khoai, bắp ngô, mặt đen nhẻm mà rộn ràng tiếng nói cười. 😽😽
Ngẫm lại thì, vèo cái đã hết một năm. Cảm ơn thật nhiều những người thân ở bên cạnh, những người anh chị em tuyệt vời luôn sát cánh và những trải nghiệm thú vị trong năm qua.
Chia tay năm cũ, chào đón năm Nhâm Dần với những thử thách và mục tiêu mới. Tết năm nay thì đúng vị rồi, rét chút và có tí mưa xuân nữa 💦💦
Chúc cho tất cả chúng ta bắt đầu một năm Nhâm Dần 2022 với nhiều điều thật mới mẻ, thật thành công, thật bình yên và thật vui tươi nhé
◼ Đặt vấn đề
Từ ngay đầu tháng qua, chú Đen đã dặn dò các Đồng âm:
- Mang tiền về cho Mẹ, đừng mang ưu phiền về cho mẹ ~~
Chú Đen mang tiền về cho mẹ thì rõ ràng rồi. Hưởng ứng chia sẻ của chú, chị bên trái mang quà về cho mẹ, các anh này mang con dâu về cho mẹ 😸😸
Quay trở lại với ReactJS
của chúng ta, không biết JSX
nhà mình mang lại điều gì cho chiếc thư viện này nhỉ? Điều gì thật sự diễn ra sau những đoạn mã JSX
đó...(suynghiii)
Khởi động năm mới với chiếc chủ đề nhẹ nhàng này cùng mình nhé 😽😽))
■ Đối tượng
Bài viết chủ yếu hướng tới các bạn đã và đang tìm hiểu về ReactJS, nhưng trong quá trình tiếp cận JSX
còn băn khoăn cũng như muốn có cái nhìn rõ nét hơn về nó.
Trong bài viết này, chúng ta sẽ cùng nhau điểm qua 03 phần
:
🔗 Overview - Tổng quan JSX
🔗 Behind the scene - Những gì diễn ra phía sau JSX
🔗 Common issues - Một số vấn đề thường gặp với JSX
Đầu tiên, cùng nhau xem lại JSX
một chút! 😺😺
■ Overview
Theo Trang chủ:
JSX
isa syntax extension
toJavaScript
.
Là cú-pháp-mở-rộng của JavaScript
, JSX
cho phép chúng ta mô tả DOM tree
cho ứng dụng dưới dạng một object
.
Ngay chính JSX Spec của React team
cũng đã đề cập:
(JSX)…to define
a concise and familiar syntax
for definingtree structures
withattributes
.
Và cũng chính vì quá đỗi quen thuộc như vậy, dẫn đến một-hiểu-lầm-khá-phổ-biến với các bạn tiếp cận với React
rằng: JSX
là HTML
. Thoáng nhìn qua, Cứ ngỡ một biến JavaScript
lại được gán giá trị là một thẻ HTML
😹😹:
const blogTitle = <h1>Make It Awesome</h1>;
Một điều lưu ý, JSX
không phải là kiểu JavaScript
tương thích với trình duyệt. Nghiễm nhiên, trình duyệt của không thể hiểu được đoạn mã này 😵😵. Đó là lý do chúng ta cần có Babel
.
Nói qua chút thì Babel
là một JavaScript compiler/transpiler
giúp chúng ta dịch đoạn JSX
trên thành JavaScript thuần
(Bạn có thể đọc tại đây nếu muốn tìm hiểu thêm nha) - đến đây thì quá là easy game
cho trình duyệt rồi 😽😽
Quá trình chuyển đổi này diễn ra trong build process
, do đó, trình duyệt sẽ không biết được sự có mặt của JSX
ngay từ đầu, thứ nó nhận được là một object
mô tả cấu trúc của ứng dụng 😸😸.
Hơn nữa, với một vài tính năng mới của ECMAScript 6
, một số trình duyệt cũ hơn vẫn chưa hiểu được, do đó, vẫn cần có Babel compiler
.
Giờ thì cùng xem thử Babel
làm như nào để được object
đó nhé (go).
■ Behind the scene
■ JSX to JS
Với component Blog
:
const Blog = () => (<h1>Make It Awesome</h1>);
sẽ được dịch thành:
const Blog = () => React.createElement( 'h1', null, 'Make It Awesome'
);
Dĩ nhiên, khi ta viết thẳng React.createElement()
mà không dùng JSX
thì component Blog
vẫn cho cùng một kết quả tương tự.
Song, với một đoạn mã nhỏ xíu như trên thì việc dùng JSX
hay React.createElement()
đều ổn hết. Trải nghiệm với React.createElement()
sẽ chưa ổn lắm khi logic quá phức tạp hoặc các elements
lồng nhau đa cấp. Trông khá khó đọc và khó bảo trì. Có lẽ JSX
sẽ nâng cao chất lượng trải nghiệm của dev hơn - với sức mạnh của HTML
và JavaScript
.
Để xem thêm cách chuyển đổi từ JSX sang React.createElement() như thế nào, bạn có thể ghé qua đây thử với các đoạn JSX cụ thể nha. 😉😉
■ React.createElement() API
Cú pháp của React.createElement() API
:
React.createElement(type, [props], [...children]);
Cùng xem qua các tham số của API này
:
type
: có thể làHTML tag
(div
,h1
, etc.),React fragment
hoặcReact component
củaelement
.props
:null
hoặc một đối tượng chứa các thuộc tính củaelement
.children
: là cácHTML tags
hoặcReact components
con củaelement
; trường hợp có nhiềuchildren
, sử dụngarray
React.createElement
sẽ tạo ra một object
đại diện cho element
đó:
{ type: 'h1', props: { children: 'Make It Awesome', ... } ...
}
Chúng ta có thể xem chi tiết các property của object này bằng cách log ra cửa sổ Console:
const Blog = () => { const blogTitle = <h1>Make It Awesome</h1>; console.log(blogTitle); return blogTitle;
};
Kết quả cho ra một plain JavaScript object
- được gọi là React element
- mô tả chính xác những gì được hiển thị lên màn hình.
FYI, có thể nói, React elements
- đại diện cho HTML elements
(nằm trên Original DOM
) - nằm trên Virtual DOM
. React
dựa vào các React elements
để tạo HTML elements
trên Virtual DOM
; Sau đó đồng bộ hóa với Original DOM
. Chi tiết về Original DOM
, Virtual DOM
, bạn có thể đọc qua bài viết này tại đây nhé!
Thêm chút props
và event
:
const dropByMyBlog = () => { /* ... */ }; const blogTitle = ( <h1 id="blogTitle" onClick={dropByMyBlog}>Make It Awesome</h1>
);
sẽ được dịch thành:
React.createElement( 'h1', { id: "blogTitle", onClick: function() { /* ... */ } }, "Make It Awesome"
);
Đoán xem object
được tạo ra có dạng như thế nào và kiểm tra lại trên Code Sandbox nhé 😸😸
■ Common issues
■ Adjacent JSX-s
Cập nhật chút component Blog
:
const Blog = () => ( <h1>Make It Awesome</h1> <p>URL: https://haodev.wordpress.com</p>
);
thì gặp ngay:
SyntaxError: Adjacent JSX elements must be wrapped in closing tag.
Lý do thì như thông báo rồi, cơ mà có bao giờ bạn tự hỏi tại sao lại như vậy!?!
Điều này cũng dễ hiểu thôi. Ở phần trước, chúng ta đã biết JSX được dịch sang React.createElement()
, hàm này tạo ra một object tương ứng, được trả về bởi component. Mà bản chất component cũng chỉ là một function. Function trong JavaScript thì chỉ trả về 1 giá trị thôi.
Do đó, component
không thể nào mà trả về 2 đối tượng ngang nhau được:
const Blog = () => ( React.createElement('h1', null, 'Make It Awesome'); React.createElement('p', null, 'URL: https://haodev.wordpress.com');
);
Để xử lý lỗi này, chúng ta có thể có 3 lựa chọn:
- Div Tag
- React Fragment
- Array Converter
Hai cách đầu có lẽ cũng không xa lạ gì:
const Blog = () => ( <div> <h1>Make It Awesome</h1> <p>URL: https://haodev.wordpress.com</p> <div>
);
hay
const Blog = () => ( <> <h1>Make It Awesome</h1> <p>URL: https://haodev.wordpress.com</p> <>
);
Cách dùng mảng thì có lẽ hơi ít gặp một chút:
const Blog = () => ( [<h1 key="blogTitle">Make It Awesome</h1>, <p key="blogURL">URL: https://haodev.wordpress.com</p>]
);
Sở dĩ chúng ta có thể làm như vậy vì trong JSX
, một đoạn <p>{[1, 2, 3, 4]}</p>
sẽ được chuyển thành <p>{1}{2}{3}{4}</p>
, 1234
vẫn được in ra bình thường không vấn đề gì 😸😸.
Chú ý thêm unique key
cho mỗi phần tử trong mảng để tránh Warning
nha ^^
Việc tại sao cần dùng key, bạn có thể tìm hiểu thêm trong bài viết này.
Trong 03 hưỡng xử lý trên thì mình hay dùng React.Fragment
(a.k.a shorthand <></>
) để bọc các Adjacent JSX-s
.
React.Fragment
được thêm vào trong React version 16.2
để tránh việc chúng ta phải dùng Div tag
trong các trường hợp không cần thiết (không có ý nghĩa trong DOM Structure
, chỉ có mục đích để tránh lỗi trên), một số khác cũng sẽ ảnh hưởng tới style
ứng dụng (flexbox
chẳng hạn). Với hướng Array Converter thì hơi khó nhìn và đòi hỏi việc kiểm soát key
.
Chốt lại thì React.Fragment
quá ư là ổn rồi đúng không nào ^^
Fragments
group a list of childrenwithout adding extra nodes
to theDOM
.
■ import React
Khi làm việc với các components
, bạn có bao giờ để ý đoạn import
quen thuộc này:
import React from 'react';
Giả sử như component
phía dưới chỉ trả về đoạn JSX
đơn giản; và cũng không sử dụng các APIs
khác trong thư viện 'react'
như useState()
, useEffect()
, etc.
Giờ thì thử xóa dòng này điii =))
Thử đoán xem kết quả sẽ như thế nào nhé...
Sẽ có hai trường hợp xảy ra:
- Hoặc vẫn chạy ngon lành
- Hoặc thông báo lỗi trong
build process
.
Vậy, lý do thật sự cho điều này là gì?
Ở phần trên, chúng ta cũng đã biết JSX
sẽ được compile
ra React.createElement()
rồi đúng không nào.
When compiled, it calls the
React.createElement()
function. So we need to haveReact
in scope forJavaScript
to know-what-to-do-with-the-compiled-code.
Khi chúng ta sử dụng JSX
, Babel compiler
sẽ chuyển chúng thành các lệnh gọi hàm React.createElement()
. Do đó, chúng ta cần có React
trong scope
hoạt động của JSX
(buộc cần import React from 'react';
).
Cho tới bản React 17.0
, Facebook team
đã "collaborate"
với Babel
, JSX
with new transform không yêu cầu điều này nữa.
It is possible to write
JSX
without importing theReact
library at the top level or havingReact
in scope.
// Inserted by a compiler (don't import it yourself!)
import {jsx as _jsx} from 'react/jsx-runtime'; const Blog = () => _jsx('h1', { children: 'Make It Awesome' });
■ Class vs. className
Chúng ta có thể thêm các thuộc tính vào các JSX elements
:
<h1 id="blogTitle" className="blog-title">Make It Awesome</h1>
Đợt nọ một người anh đố mình , tại sao chúng ta phải dùng className
thay vì class
!?!
Mạnh dạn sửa thành class="blog-title"
nhận ngay chiếc
Warning: Invalid DOM property 'class'.
Hmm...
Tại sao nhỉ? (thinking)
Trong JavaScript
, class
là từ khóa dùng để khai báo lớp, do đó, việc truy cập props.class
dẫn đến Warning
như trên.
■ Kết
Yayyy... Như vậy là chúng ta đã cùng nhau tìm hiểu về JSX
và vài điều thú vị diễn ra xung quanh nó rồi.
Hy vọng rằng bài viết này có thể giúp ích được các bạn đã và đang tiếp cận với ReactJS
. Có thể nói rằng, JSX
chẳng phải từ khóa khó tiếp cận với người mới, ấy thế nhưng, cùng nhau tìm hiểu thêm chút để giải thích Tại sao thế này, Tại sao thế kia? để nắm được bản chất thì cũng thú vị nhỉ ^^
Cảm ơn các bạn đã đọc bài chia sẻ này. Đầu xuân năm mới, lì xì mình 1 upvote
để có thêm động lực cho những bài viết sắp tới nhé 😺😺
Và trong thời điểm hiện tại thì...
Mặc dù thời gian này (thời điểm mình publish
bài viết, 01/02/2022), các tỉnh đã có các biện pháp phòng tránh, kiểm soát tình hình dịch bệnh; Việc tiêm vaccine Covid-19
cũng đã được triển khai, song, đang trong thời gian nghỉ Tết Âm lịch nên nhu cầu di chuyển của người dân là không thể tránh khỏi, chúng ta cũng chưa thể chủ quan, hãy tiếp tục tuân thủ quy tắc 5K
được Bộ Y tế
khuyến cáo:
#Coronavirus #5K #BoY Te
Khẩu trang - Khử khuẩn - Khoảng cách - Không tập trung - Khai báo y tế
để có thể giữ an toàn cho bản thân và mọi người xung quanh 😺😺
Một lần nữa, chúc các bạn kì nghỉ Tết ấm áp, đong đầy hạnh phúc bên gia đình nhé!
Năm mới ghé qua nhà mình "thưởng bánh uống trà" chút rồi về ^^
■ Credits
- Resources: React document, Yogesh Chavan's post via Freecodecamp, Ryan Harris's post via Freecodecamp, Ifeoma Imoh's post via Progress Telerik.
- Thumbnail: Đen - Mang Tiền Về Cho Mẹ ft. Nguyên Thảo (M/V), cuongkhung1993 via Reddit.
- Policies:
- This original article from My Make It Awesome blog.
- Use my contents for sharing purpose, please attached resource linked to my blog.
- Use my contents for trading purpose, please contact me.
- Support: Buy me a pizza.
- Copyright: The posts in a spirit of sharing knowledge. If there is anything with regard to copyright of your contents, please contact me.
Happy coding!