Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Xây dựng nhanh ứng dụng Rails tương tác với Hotwire: Hướng dẫn cho người mới

Hotwire là chủ đề nóng hổi hiện nay đối với mọi nhà phát triển Rails. Nếu bạn làm việc với Rails, có khả năng cao bạn đã nghe nhiều về nó.

Hotwire là cách hoàn toàn mới để thêm tính năng tương tác vào ứng dụng với rất ít dòng mã, và nó hoạt động cực nhanh bằng cách truyền HTML qua đường dây (over the wire). Điều đó có nghĩa là bạn có thể giữ tay "sạch" khỏi hầu hết các framework Single Page Applications (SPA). Bạn cũng có thể giữ logic rendering tập trung trên server, trong khi vẫn duy trì thời gian tải trang nhanh và tính tương tác.

Trong bài viết này, chúng ta sẽ xem các thành phần chính của Hotwire và cách dùng nó trong ứng dụng Rails. Nhưng trước hết: Hotwire là gì và tại sao nên dùng nó?

Hotwire là gì?

Hotwire không phải một thư viện đơn lẻ, mà là cách tiếp cận hoàn toàn mới để xây dựng ứng dụng web và di động bằng cách gửi HTML qua đường dây. Nó bao gồm Turbo, Stimulus, và Strada (sẽ ra mắt cuối năm nay). Chúng ta sẽ thảo luận chi tiết từng thành phần ở phần tiếp theo.

Ghi chú thêm: Mặc dù Hotwire gắn liền với Rails, nó hoàn toàn phi ngôn ngữ (language-agnostic), nên hoạt động tốt như nhau với các ứng dụng khác. Tôi đã dùng Stimulus trong production trên một số ứng dụng non-Rails và trang web tĩnh. Bạn cũng có thể dùng Turbo không cần Rails.

Nhưng hãy quay lại thế giới Rails cho lúc này.

Tại sao dùng Hotwire trong ứng dụng Rails của bạn?

Vậy khi nào nên dùng Hotwire? Câu trả lời là bất cứ đâu bạn muốn thêm tính năng tương tác vào ứng dụng. Ví dụ, nếu bạn muốn:

  • Một số nội dung hiển thị/ẩn có điều kiện dựa trên tương tác của user (ví dụ: form địa chỉ nơi danh sách bang/thành tự động thay đổi dựa trên quốc gia được chọn).
  • Cập nhật nội dung theo thời gian thực (ví dụ: feed như Twitter nơi tweet mới tự động thêm vào trang).
  • Tải lười (lazy-load) một số phần trang (ví dụ: bên trong accordion, bạn tải tiêu đề và đánh dấu chi tiết để tải lười, tăng tốc độ tải trang).

Các thành phần của Hotwire

Như đã nói, Hotwire là tập hợp các kỹ thuật mới (và một số cũ) để xây dựng ứng dụng web.

Hãy thảo luận từng thành phần ở các phần tiếp theo.

Turbo

HTML điều khiển Turbo ở lõi. Turbo cung cấp một số kỹ thuật để xử lý dữ liệu HTML đến qua đường dây và hiển thị trên ứng dụng mà không cần tải lại toàn trang. Nó bao gồm:

  • Turbo Drive

    Nếu bạn từng dùng Turbolinks trước đây, bạn sẽ cảm thấy như ở nhà với Turbo Drive. Ở lõi, một số mã JS chặn sự kiện JavaScript trên ứng dụng, tải HTML bất đồng bộ (asynchronously), và thay thế các phần của HTML markup.

  • Turbo Frames

    Turbo Frames tách các phần markup của bạn thành các section riêng biệt có thể tải độc lập.

    Ví dụ, nếu bạn có ứng dụng blog, nội dung bài viết và bình luận là hai phần liên quan nhưng độc lập của trang. Bạn có thể tách chúng để điều hướng hoạt động độc lập hoặc thậm chí tải chúng bất đồng bộ với turbo frames.

  • Turbo Streams

    Turbo Streams cung cấp tiện ích để dễ dàng mang dữ liệu thời gian thực vào ứng dụng. Ví dụ, giả sử bạn xây dựng news feed như Twitter. Bạn muốn kéo tweet mới vào feed của user ngay khi đăng mà không tải lại trang. Turbo Streams cho phép bạn làm điều này mà không viết một dòng JS nào.

  • Turbo Native

    Turbo Native cho phép bạn xây dựng wrapper native quanh ứng dụng web. Điều hướng và tương tác sẽ cảm thấy native mà không cần làm lại tất cả màn hình native.

    Bạn sẽ tiếp tục phân phối phần còn lại của ứng dụng qua web. Cách đó, bạn có thể tập trung vào phần thực sự tương tác của ứng dụng và làm cho nó đúng đắn.

Stimulus

Stimulus là framework JavaScript để viết controller tương tác với HTML của bạn.

Giả sử chúng ta cần thêm một số thuộc tính JavaScript như data-controller, data-action, và data-target vào các phần tử trên trang. Chúng ta sẽ viết một stimulus controller có quyền truy cập vào các phần tử nhận sự kiện dựa trên những thuộc tính đó. Ví dụ:



Rất dễ hình dung việc này làm gì mà không cần đọc controller Stimulus liên quan.

Đây là controller đi kèm với HTML:



Đó là cốt lõi của Stimulus: giữ mọi thứ đơn giản và tái sử dụng được.

Bây giờ, nếu bạn bao giờ cần nút copy-to-clipboard trên trang khác, bạn chỉ cần tái sử dụng controller đó. Thêm thuộc tính data-* trên markup để mọi thứ hoạt động.

Strada

Rất tiếc, chúng ta chưa biết nhiều về Strada. Nhưng nó sẽ cho phép ứng dụng web giao tiếp (và có thể thực hiện hành động) với ứng dụng native dùng thuộc tính cầu nối HTML (HTML bridge attributes).

Cách dùng Hotwire trong ứng dụng Ruby on Rails của bạn

Tôi không muốn dành quá nhiều thời gian thảo luận cài đặt Hotwire hoặc trường hợp dùng cơ bản. Đội ngũ Hotwire đã làm xuất sắc việc này trong screencast Hotwire của họ. Để hướng dẫn đầy đủ, xem cài đặt turbo-rails và cài đặt Stimulus.

Hãy nhảy thẳng vào một số trường hợp dùng Hotwire phổ biến.

Cuộn vô tận (Endless Scroll)

Dùng Turbo Frames, chúng ta dễ dàng tạo trang với phân trang tự động khi user cuộn. Cho việc này, cần làm hai điều:

  1. Render mỗi "trang" bên trong frame riêng bằng cách thêm số trang vào frame id (ví dụ: turbo_frame_tag "posts_#{@posts.current_page}").
  2. Dùng frame lazy cho trang tiếp theo để nó không tải tự động trừ khi nó xuất hiện trong tầm nhìn.


Lưu ý ví dụ này dùng phương thức từ Kaminari, nhưng bạn có thể điều chỉnh cho bất kỳ phương pháp phân trang nào khác.

Chúng ta không cần gì đặc biệt trong controller. Một phương thức index tiêu chuẩn hoạt động:



Mánh khóe ở đây là chúng ta dùng frame lồng nhau (nested frames), với frame cho trang tiếp theo lồng bên trong frame trang trước. Khi trang đầu tải, frame trang tiếp theo được đặt ở cuối. Khi user cuộn đến frame đó, nó được thay thế bằng nội dung trang hai. Frame lazy cho trang ba render ở cuối.

Form động (Dynamic Forms)

Bạn có thể dễ dàng triển khai form động với Hotwire mà không cần logic tùy chỉnh để bật/tắt trường ở frontend. Trường hợp này phức tạp hơn endless scroll, vì bao gồm cả Turbo Stream và Stimulus.

Hãy bắt đầu với form của chúng ta.



Form đủ đơn giản — hiển thị select kind với tùy chọn News và Blog. Chúng ta muốn thay đổi giá trị danh mục (categories) khả dụng dựa trên kind được chọn (giả sử categories_for_kind(@post.kind) trả về danh sách danh mục cho kind đã cho).

Nếu nhìn kỹ, bạn sẽ thấy chúng ta đã thêm một số thuộc tính data vào form. data-target sẽ liên kết phần tử form với target form của RefreshFormController Stimulus Controller. Và data-action với giá trị change->refresh-form#refreshForm sẽ gọi phương thức refreshForm trên Stimulus Controller đã liên kết mỗi khi select kind thay đổi.

Hãy xem Stimulus Controller của chúng ta:



Trên mọi lần gọi refreshForm, chúng ta chỉ tạo yêu cầu PUT mới đến URL controller (đặt bằng data-refresh-form-url trên cùng phần tử với data-controller="refresh-form"). Phần quan trọng là responseKind được đặt thành turbo-stream. Thư viện @rails/request hiểu phản hồi này và thực hiện hướng dẫn dựa trên response stream.

Bây giờ tất cả còn lại là trả về stream đúng từ lời gọi refresh_form cho Turbo hiểu và cập nhật form.



Chỉ cần cập nhật thuộc tính trên post và đánh dấu muốn phản hồi ở định dạng turbo_stream (để nó tra cứu refresh_form.turbo_stream.erb).



Ở bước này, chúng ta tái sử dụng partial form, bọc nó bên trong turbo_stream với hành động replace.

Và đó là tất cả bạn cần để có form động hoạt động. Tôi biết trông hơi nâng cao, nhưng refresh stimulus controller là phần dùng chung giờ bạn có thể dùng cho tất cả form động bằng cách thêm đúng thuộc tính data-*. Vì vậy, về cơ bản, bạn giờ có server-side dynamic form refresh mà không viết JS mới cho form khác. Pretty awesome, đúng không?

Thêm nội dung vào trang mà không tải lại (Append Content to Pages Without Reloading)

Trường hợp dùng tiếp theo Hotwire làm dễ dàng là streaming HTML qua kết nối WebSocket và cập nhật trang với nội dung mới khi nó đến. Ví dụ tốt là phần bình luận GitHub. Bạn có thể triển khai rất dễ dàng dùng Turbo Streams.

Có hai phần cho việc này.

Thứ nhất, nhúng turbo stream listener trên trang danh sách mở kết nối WebSocket đến server và lắng nghe sự kiện.



Tiếp theo, cập nhật model để broadcast bình luận mới đến stream.



Bạn không cần gì khác. Turbo sẽ tự động render partial app/views/comments/_comment.html.erb cho mỗi bình luận mới và gửi qua kết nối WebSocket. Nó sẽ được JS của Turbo nhặt lên và prepend vào target với id comments.

Hãy đi một bước nữa và thêm chỉ báo cho tất cả bình luận mới thêm với một Stimulus Controller nhỏ.

Thứ nhất, sửa đổi broadcast và partial comment để bao gồm controller có điều kiện.




Stimulus controller nhỏ này thêm class highlight đặc biệt khi kết nối trong 3 giây rồi gỡ bỏ nó.



Lưu ý: Bạn cũng cần cập nhật CSS highlight dựa trên sự hiện diện của class đó.

Khi controller này xong, bạn có thể tái dùng nó cho bất cứ thứ gì cần class highlight. Bạn thậm chí có thể sửa đổi để lấy duration và tên class từ thuộc tính data nếu cần sự linh hoạt đó.

Đó là điều tuyệt vời về Hotwire — nó đưa bạn rất xa, và bạn không cần chạm tay vào JS. Khi bạn cần viết JS, Stimulus cho bạn công cụ xây dựng controller nhỏ, chung, có thể tái sử dụng.

Tổng kết và Đọc thêm

Cộng đồng Rails đã thực sự hào hứng với sự ra mắt của Hotwire, và đúng vậy.

Trong bài này, chúng ta xem các thành phần chính của Hotwire và cách dùng Hotwire trong ứng dụng Rails. Chúng ta chạm đến cách đưa ứng dụng đến cuộc sống dùng Turbo và Stimulus.

Screencast giới thiệu Hotwire chính thức và tài liệu Turbo là nơi tuyệt vời để xem Hotwire và Turbo có thể làm gì cho bạn.

Để dùng nâng cao, tôi đề xuất truy cập repo turbo-rails trên GitHub. Thật tiếc tài liệu hơi thưa, nhưng nếu bạn không ngại bẩn tay, hãy đọc mã và comment inline trong:

  1. Turbo::FramesHelper cho Turbo Frames.
  2. Turbo::Broadcastable cho broadcasting đến Turbo Streams từ mã.
  3. Turbo::Streams::TagBuilder cho broadcasting đến Turbo Streams như một phần của hành động controller inline.

Happy coding!

P.S. Nếu bạn muốn đọc bài Ruby Magic ngay khi xuất bản, hãy đăng ký newsletter Ruby Magic của chúng tôi và đừng bỏ lỡ bất kỳ bài nào!

Xây dựng nhanh ứng dụng Rails tương tác với Hotwire: Hướng dẫn cho người mới

Sapan Diwakar

Tác giả khách Sapan Diwakar là nhà phát triển full-stack. Anh viết về sở thích trên blog và là fan hâm mộ lớn của việc giữ mọi thứ đơn giản, trong cuộc sống và trong mã. Khi không làm việc với công nghệ, anh thích dành thời gian trong vườn, đi rừng, và chơi thể thao ngoài trời.

Tất cả bài viết của Sapan Diwakar