About Github view_component gem (https://github.com/github/view_component) (Here I don't mention component architecture but write directly about view_component gem because for each library, the component architecture will be implemented differently at some point)
Advantages: (See more here: https://github.com/github/view_component#why-should-i-use-components)
(1) Encourage separating logic from views and reside them in a ruby class
(2) Removed the ability to use an instance variable (@) in partial, view_component requires passing variables from outside through new
) => Finding the origin of the variable is easier
(3) view_component ~ 10 times faster than partial (https://github.com/github/view_component/blob/master/performance/benchmark.rb)
(4) Easily reuse view_component template by inherit from another component
(5) Unit-test view_component fast + easier than partial
(6) view_component encourages coupling CSS & JS with the component
Although they are advantages, if analyzed carefully, not every point is sounds:
- For (1) and (2), although view_component limits the disadvantages of helpers & partials. However, there are ways to repeat the old mistakes. For example:
# 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 I might be out of my original context"
- In the above example, we can see that since we can access
controller
when subclass ViewComponent::Base, we can accessvar_1
- created by the controller. So if the controller is having problems with too many places that can setvar_1
, it can still lead to subtle & hard to detect bugs when rendering post_index_component in a different context from the original one. To handle this bad practice, we need conventions for our source code and view_component can't help in this case. By using convention, we can handle this bad practice even if we use partial, for example:
For partials:
- Only use the variable from local_assigns to render the interface
- Do not use ruby to set variables out of the partial scope
For view_component:
- Only use variables passed in initialize to render interfaces
- Do not set variables outside the scope of the component
In short, in my opinion, (1) and (2) - the advantage of data flow mentioned in https://github.com/github/view_component#data-flow should not be considered the advantage of view_component over partial
-
For (5), unit testing for view_component is not really beneficial. See https://dhh.dk/2014/test-induced-design-damage.html and https://signalvnoise.com/posts/3159-testing-like-the-tsa, 2 posts from RoR's creator. Unless we want to use Unit-test to protect the base components of our design system.
-
For (3), (4), (6) it is correct
Furthermore, the component architecture encourages the splitting of the view into multiple components for reuse, extension + application of the design system. So, if we simply convert partial to a component with a corresponding name, I think we have missed a very important part of the component architecture. See how GitHub builds view_component (https://github.com/primer/view_components) for their Primer Design System similar to Primer React (https://github.com/primer/components)