Skip to content

Instantly share code, notes, and snippets.

@vuongpdz
Created October 8, 2020 08:01
Show Gist options
  • Save vuongpdz/b202a09294681bb5c222020bcd2ddeba to your computer and use it in GitHub Desktop.
Save vuongpdz/b202a09294681bb5c222020bcd2ddeba to your computer and use it in GitHub Desktop.
Report on view_component Gem & component architecture in Rails

REPORT VIEW_COMPONENT

Về Github view_component gem (Ở đây em không nhắc chung tới kiến trúc component nữa mà nói trực tiếp tới view_component gem vì đối với mỗi thư viện, kiến trúc component sẽ được thực hiện khác nhau ở 1 số điểm)

Ưu điểm: (Xem thêm ở đây: https://github.com/github/view_component#why-should-i-use-components)

(1) Tách biệt logic ra khỏi views và nằm trong 1 ruby class riêng biệt

(2) Loại bỏ khả năng sử dụng 1 biến instance (@) ở trong nhiều partials như trước đây (bắt buộc phải truyền biến từ ngoài vào component) => Việc tìm nguồn gốc của biến sử dụng dễ dàng hơn

(3) view_component nhanh hơn partials ~10 lần (https://github.com/github/view_component/blob/master/performance/benchmark.rb)

(4) Dễ dàng tái sử dụng view_component template bằng cách inherit từ component khác

(5) Unit-test view_component nhanh + dễ dàng hơn partial

(6) view_component khuyến khích việc cấu trúc CSS & JS đi theo component

Tuy là ưu điểm nhưng nếu phân tích kỹ ra thì cũng không ưu lắm:

  • Đối (1) và (2), mặc dù có cản trở được nhược điểm của helpers & partials tuy nhiên không phải là không có cách để vẫn mắc lại những lỗi cũ này. Ví dụ:
# controllers/posts_controller.rb
class PostsController < ApplicationController
  attr_accessor :var_1

  def show
    @post = Post.find(params[:id])
    render(PostShowComponent.new(post: @post))
  end

  def index
    @posts = Post.all
    render(PostIndexComponent.new(post: @post))
  end
end

# component/base_component.rb
class BaseComponent < ViewComponent::Base
  delegate :var_1, to: :controller
end

# components/post_index_component.rb
class PostIndexComponent < BaseComponent

end

# components/post_index_component.html.slim
= var_1 = "haha, I changed it even if others might need it not to be changed"
= "I'm trying to reuse #{var_1.to_s} even if it's might be out of its original context"
  • Trong ví dụ trên ta thấy do chúng ta có thể truy cập controller khi subclass ViewComponent::Base cho nên chúng ta hoàn toàn có thể truy cập var_1 - được tạo ra bởi controller. Vì vậy nếu trong controller đang gặp vấn đề về việc có quá nhiều nơi đang thay đổi var_1 thì cũng vẫn sẽ dẫn tới có bug khó debug khi render post_index_component ở view khác với view ban đầu nó được sử dụng (tương tự như với partial). Để xử lý bad practice này thì cần convention cho source code chứ view_component không thể giúp mình được. Với convention thì ta có thể xử lý được bad practice này với cả partial và view_component, ví dụ:

Đối với partials:

  • Chỉ nê sử dụng biến từ local_assigns để render giao diện
  • Không xài ruby để set biến ra ngoài phạm vi của partial

Đối với view_component:

  • Chỉ được sử dụng biến truyền vào initialize để render giao diện
  • Không set biến ra ngoài phạm vi của component

Nói tóm lại, theo quan điểm của em thì (1) và (2) - ưu điểm về data flow được nhắc tới trong https://github.com/github/view_component#data-flow không nên được coi là ưu điểm của view_component so với partials

Còn nữa, kiến trúc component khuyến khích việc chia nhỏ view thành nhiều component để có thể sử dụng lại, mở rộng + áp dụng design system. Vậy nên, nếu chỉ đơn giản chuyển đổi partial thành component có tên tương ứng thì em nghĩ là mình đã bỏ qua 1 phần rất quan trọng của kiến trúc component. Tham khảo cách GitHub xây dựng view_component (https://github.com/primer/view_components) cho Primer Design System của họ tương tự Primer React (https://github.com/primer/components)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment