Chú Đen mang tiền về cho mẹ còn JSX mang gì về cho React?

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

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 is a syntax extension to JavaScript.

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 defining tree structures with attributes.

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: JSXHTML. 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:

constBlog=()=>(<h1>Make It Awesome</h1>);

sẽ được dịch thành:

constBlog=()=> 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 HTMLJavaScript.

Để 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ặc React component của element.
  • props: null hoặc một đối tượng chứa các thuộc tính của element.
  • children: là các HTML tags hoặc React components con của element; trường hợp có nhiều children, sử dụng array

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:

constBlog=()=>{const blogTitle =<h1>Make It Awesome</h1>;
    console.log(blogTitle);return blogTitle;};

Open in ⇱Code Sandbox.

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 propsevent:

constdropByMyBlog=()=>{/* ... */};const blogTitle =(<h1id="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:

constBlog=()=>(<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:

constBlog=()=>(
    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ì:

constBlog=()=>(<div><h1>Make It Awesome</h1><p>URL: https://haodev.wordpress.com</p><div>
);

hay

constBlog=()=>(<><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:

constBlog=()=>([<h1key="blogTitle">Make It Awesome</h1>,<pkey="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 children without adding extra nodes to the DOM.

■ 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 have React in scope for JavaScript 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 the React library at the top level or having React in scope.

// Inserted by a compiler (don't import it yourself!)import{jsx as _jsx}from'react/jsx-runtime';constBlog=()=>_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:

<h1id="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

Happy coding!

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ