ReactJS từ góc nhìn của người lập trình Frontend

3226

Mở đầu

Tôi là một lập trình viên thích làm Frontend (chắc là ai cũng biết nó là các thứ như HTML, CSS và Javascipt). Tất nhiên cũng chỉ ở dạng xoàng xĩnh thôi.

Ngày tôi bắt đầu học làm Frontend, người ta cũng bảo tôi là nên học Javascipt trước rồi hãy học Jquery. Tuy nhiên, sự đơn giản và tiện dụng của Jquery đã khiến tôi làm điều ngược lại, học Jquery và chỉ quay lại tìm hiểu thêm về Javascipt (không có Jquery) khi cần thiết.

Càng học và làm việc với Jquery và các thư viện của nó nhiều tôi càng thấy Jquery toàn năng. Đúng như tiêu chí “Write Less, Do More”, Jquery (và các thư viện đi kèm) rất dễ đọc, dễ viết, dễ sửa, cộng đồng sử dụng lớn… Và tôi dùng Jquery để giải quyết hầu hết các vấn đề gặp phải trên Frontend.

Gần đây, người ta hay nhắc đến và tán dương React – một thư viện Javascript được phát triển bởi Facebook. Sau khi tham dự một buổi seminar ngắn của một bạn cùng công ty về React, tôi bị ấn tượng khá mạnh về VIRTUAL DOM và DATA FLOW của thư viện này. Tôi hình dung ra những bài toán Frontend mình gặp từ trước đến nay, và có một số vấn đề có vẻ khá sáng sủa nếu làm bằng React. Vì vậy tôi quyết định đặt ra một bài toán nhỏ và thử giải quyết bằng React – một người bạn mới gặp lần đầu.

Bài toán

Hình vẽ dưới là hình dung về trang HTML đơn giản này, người dùng có thể thêm sản phẩm bằng cách chọn trong selection box, xoá bằng nút [X], thay đổi số lượng bằng các nút [+] và [-]. Giá ở cột Price và hai vị trị Total sẽ được cập nhật ngay khi có thay đổi trong giỏ hàng.

1.jpg

Để có một hình dung tốt nhất về bài toán, đây là link của sản phẩm đã hoàn thành.

https://jsfiddle.net/bs90/189txdh2/29/embedded/result/

Bài viết này tôi chỉ đi sâu vào chia sẻ luồng tư duy của cá nhân tôi trong việc giải quyết bài toán này với React, chứ không đi sâu vào việc phân tích viết code thế nào và tại sao nó chạy.

Giải quyết bài toán

Nếu như bình thường, việc đầu tiên tôi sẽ làm là viết HTML và CSS, sau đó bắt đầu viết JavaScript( Jquery). Tuy nhiên, việc đầu tiên cần làm với React là thiết kế các Vitual DOM.

Ai biết về HTML chắc hẳn cũng sẽ biết khái niệm DOM (Document Object Model), ví dụ đơn giản nhất là một trang HTML cũng là một DOM đã được trình duyệt dịch ra và hiển thị, một cấu trúc cây gồm gốc là thẻ html, hai con là thẻ head và thẻ bodyhead thì có con là thẻ titlemetabody thì có con là thẻ diva… Thông thường chúng ta sẽ viết Javascipt tác động trực tiếp lên các thành phần của DOM trên view để thay đổi chúng.

React cung cấp một khái niệm tên là Vitual DOMVitual DOM – DOM ảo đúng như tên gọi của nó, chứa toàn bộ các thông tin cần thiết để tạo nên một DOM, tuy nhiên lại nằm hoàn toàn trong code Javascript cho phép chúng ta tạo, xoá, sửa, thực hiện đủ loại thao tác trên nó trước khi được render thành (real)DOM trên view.

Tại sao nên dùng Vitual DOM? Bạn có thể search trên VIBLO. Đã có sẵn một số bài viết về vấn đề này.

Chính vì dùng Vitual DOM nên file HTML của tôi lần này sẽ chẳng có nội dung gì trong thẻ body cả, điều kỳ lạ đầu tiên!

Thiết kế cấu trúc Vitual DOM

Quay lại việc thiết kế các Vitual DOM đã nói ở trên. Việc thiết kế này, hay là việc tách các thành phần trong nội dung trang ra thành các React Class riêng theo cấu trúc cây, giúp cho ta có một hình dung mạch lạc về luồng dữ liệu (DATA FLOW) của bài toán.

Lần này tôi thiết kế như hình vẽ dưới đây.

2.jpg

Root là CartDiv, nó chính là cái sẽ được render vào trong thẻ body của trang. CartDiv có hai con là Banner và ItemTableBanner là phần banner của trang, có phần title và phần tổng giá tiền TOTAL, phần này đơn giản nhất là cho vào trong CartDiv luôn, nhưng tôi muốn tách ra để có cơ hội nắm rõ về Data Flow của ReactItemTable là phần bảng còn lại, mỗi thẻ tr chứa thông tin của một sản phẩm tôi lại cho thành 1 con của ItemTable, tên là OneItem.

Giải thích về Data Flow thì không có gì dễ bằng bắt tay vào code và thuyết mình về nó. Đầu tiên là phần CartDiv

Đó là trạng thái sơ khai nhất, cho chúng ta nhìn thấy là CartDiv chứa hai React Class con là Banner và ItemTable. Bây giờ chúng ta xem xét về data, one-way binding của React yêu cầu data phải truyền từ cha xuống con, data ở đây không chỉ là các biến mà còn là cả các method nữa. Chúng ta phân tích từ từ xem cần truyền gì từ CartDiv xuống cho Banner và ItemTable?

Banner thì đơn giản, truyền cho nó cái tổng tiền là xong. ItemTable thì phức tạp hơn một chút, ngoài tổng tiền thì còn phải truyền thông tin về sản phẩm đang ở trong giỏ hàng kèm theo số lượng và thông tin sản phẩm chưa được mua nữa.

Thêm những phần đó thì class CartDiv sẽ thành như sau.

total_costitems và left_items sẽ được khởi tạo trong hàm getInitialState

Tạm ổn như thế, chúng ta sẽ đi xây dựng hai class con Banner và ItemTableBanner thì quá đơn giản như sau.

Về ItemTable thì tôi thiết kế nó là một HTML Table, nhận thấy khi có sản phẩm thì cấu trúc của các thẻ tr hiển thị một sản phẩm là như nhau. Vì vậy tôi quyết định viết một class khác tên là OneItem. Phần ItemTable tôi viết như dưới đây.

OneItem thì khá đơn giản, nó chỉ là 1 dòng tr với số thứ tự, thông tin sản phẩm và các nút [+][-]để tăng giảm số lượng, nút [X] xoá sản phẩm mà thôi.

Như vậy là chúng ta thiết kế xong cấu trúc theo hình vẽ bên trên. Chạy thử bây giờ nó sẽ ra trạng thái đầu tiên của link https://jsfiddle.net/bs90/189txdh2/29/embedded/result/, tuy nhiên chả button nào hoạt động cả. Đó chính là việc tiếp theo chúng ta cần làm, làm cho các button hoạt động.

Thiết kế sự kiện (event) – làm cho các button hoạt động

Nếu mà cứ giữ như trên thì viết luôn 1 cái trang HTML tĩnh là xong, chả phải mất công chia chác làm gì cả. Giờ là lúc làm cho mọi thứ hoạt động.

Chúng ta cùng nhau phân tích các sự kiện có thể diễn ra trong trang hiện tại. Cũng không nhiều.

  • Sự kiện thêm hàng vào giỏ
  • Sự kiện xoá hàng khỏi giỏ
  • Sự kiện thay đổi số lượng của từng mặt hàng trong giỏ

Như đã nói ở trên, các method cũng sẽ được truyền từ cha xuống con, vì vậy chúng ta sẽ viết các method ứng với mỗi sự kiện ở class CartDiv.

Và 3 methods này sẽ được truyền xuống cho các con cần dùng đến nó.

Chuẩn bị xong phần methods, bây giờ chúng ta làm nốt phần cuối cùng, bắt các sự kiện vào các methods đó. Cùng xem lại các sự kiện có thể xảy ra.

  • Sự kiện thêm hàng vào giỏ → Chọn ở selection box (1) và ấn nút submit form (2)
  • Sự kiện xoá hàng khỏi giỏ → Ấn vào nút [X] (3)
  • Sự kiện thay đổi số lượng của từng mặt hàng trong giỏ → Ấn vào nút [+] hoặc [-] (4)

Vậy là có 4 events tất cả. Chúng ra bổ sung code cho 4 event này.

SAVE! And you done! https://jsfiddle.net/bs90/189txdh2/29/embedded/result/

Bạn có thể xem và nghịch source code tôi đã viết tại đây http://jsfiddle.net/bs90/189txdh2/29/

Mọi thứ diễn ra khá dễ dàng phải không các bạn!

Nếu giải quyết bằng JQuery?

Như tôi có nói ban đầu, với tôi JQuery là toàn năng, sau khi biết về React điều này vẫn không có thay đổi. Tuy nhiên lượng vấn đề trên FrontEnd tôi giải quyết bằng JQuery có lẽ sẽ giảm đi, thay vào đó tôi sẽ dùng React.

Ví dụ như bài toán bên trên, nếu làm bằng Jquery, việc xử lý các hành động diễn ra sẽ khá là mệt mỏi. Hành động xoá sản phẩm đi chẳng hạn, ngoài việc tính toán lại hai mảng chứa sản phẩm như làm bằng React, chúng ta sẽ phải cập nhật hai giá trị Total, tìm đúng hàng chứa sản phẩm để xoá nó đi khỏi bảng, sau đó còn phải tính toán lại để hiển thị số thứ tự cho đúng. Ngoài ra cũng còn tương đối những rắc rối khác nữa. Thực ra ban đầu rồi định giải quyết bài toán này bằng cả JQuery nữa để có một phép so sánh chính xác nhất. Tuy nhiên nghĩ đến nhức rắc rối trên, tôi quyết định từ bỏ. Trong bài toán này, việc React hoàn toàn vượt trội là điều dễ nhìn thấy.

Tất nhiên bạn có thể thắc mắc rằng, nếu không dùng React vẫn có thể xây dựng được một hàm render tương tự như React, mỗi khi có thay đổi cũng chỉ cần chạy hàm render đó là xong? Không sai, nhưng các kỹ sư của Facebook đã kỳ công nghiên cứu và cải tiến các thuật toán để Vitual DOMcủa React trở nên siêu nhanh thì tại sao chúng ta không dùng! React nhanh ra sao các bạn có thể tìm trong Viblo và tham khảo các bài viết khác.

Kết luận

Sau một quá trình ngắn tìm hiểu và làm thử React, tôi thấy nó khá phù hợp với một lập trình viên thích làm FrontEnd như tôi. Cấu trúc và cách viết React khá sáng sủa, tuy nhiên lại đòi hỏi người viết có một tư duy lập trình ở một mức nhất định.

Những bài toán nhỏ, những hệ thống chỉ có một chút UI cần dùng đến Javascipt tôi nghĩ không nên dùng ReactReact thích hợp hơn với những hệ thống vừa và lớn, yêu cầu khả năng duy trì và mở rộng cao. Việc phân tích cấu trúc, kết nối các thành phần stateless cũng khá đau đầu và mất thời gian, tuy nhiên nếu làm được chúng ta sẽ có một hệ thống được cấu trúc tốt, đẹp và dễ dàng duy trì và mở rộng.

TL,DR? Cảm ơn các bạn đã đọc bài viết của tôi. Chúc các bạn thành công với React!

Techtalk via viblo

CHIA SẺ