[Rails] Comparing the Performance of ViewComponent and Partial
Published: 2023-12-21 10:30:00

There's a lot of information out there about Rails' partial, with some claiming it degrades performance, while others argue that in production environments the impact isn't significant. There are also views suggesting that using view_component can enhance performance, but again, opinions vary. I was unsure which information was accurate, so I decided to conduct some measurements.

## Testing Methodology
- Output the same content using direct coding, partial, partial with collection, and view component
- Measure performance in a development environment
- Measure performance in a production environment

## Environment Setup
```shell
$ ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]
$ rails -v
Rails 6.1.3.1
```
```ruby
# Gemfile
gem "view_component", require: "view_component/engine"
```
```shell
$ bundle install
$ rails g controller samples vanilla partial partial_collection view_component
$ rails g model sample name:string
$ rails db:migrate
```
```ruby
# app/controllers/samples_controller.rb
class SamplesController < ApplicationController
  before_action :build_samples
  def vanilla
  end

  def partial
  end
  
  def partial_collection
  end

  def view_component
  end
  
  def build_samples
    @samples = Sample.all
  end
end
```
```ruby
# db/seed.rb
100.times do |n|
  Sample.create!(name: "user#{n}")
end
```
```shell
$ rails db:seed
```

### vanilla
```erb
# app/views/samples/vanilla.html.erb
<% @samples.each do |sample| %>
  <p><%= sample.name %></p>
<% end %>
```
### partial
```shell
$ touch app/views/samples/_hoge.html.erb
```
```erb
# app/views/samples/_hoge.html.erb
<p><%= hoge.name %></p>
```
```erb
app/views/samples/partial.html.erb
<% @samples.each do |sample| %>
  <%= render 'hoge', hoge: sample %>
<% end %>
```
### partial(collection)
```erb
# app/views/samples/partial.html.erb
<%= render partial: 'hoge', collection: @samples, as: 'hoge' %>
```
### view_component
```shell
$ rails g component Hoge hoge
```
```ruby
# app/components/hoge_component.rb
class HogeComponent < ViewComponent::Base
  def initialize(hoge:)
    @hoge = hoge
  end
end
```
```erb
# app/components/hoge_component.html.erb
<p><%= @hoge.name %></p>
```
```erb
# app/views/samples/hoge_component.html.erb
<% @samples.each do |sample| %>
  <%= render(HogeComponent.new(hoge: sample)) %>
<% end %>
```

https://github.com/nyshk97/partial-view-components

## Measurements
Accessed samples/vanilla, samples/partial, and samples/view_component, and checked the following parts of the log.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2zosoi5rgt6makqd5kb1.png)

### Local Environment
Accessed each 5 times and recorded the median value.

|  | Result  |
|---|---|
|vanilla  |8.7ms  |
|partial  |23.3ms  |
|partial_collection  |8.5ms  |
|view_component  |9.2ms  |

### Production
Accessed each 11 times and recorded the median value.
The server used was Heroku.

|  | Result  |
|---|---|
|vanilla  |5.3ms  |
|partial  |10.7ms  |
|partial_collection  |4.45ms |
|view_component  |5.55ms  |

## Summary and Thoughts
- In both local and production environments, using view_component with each loop offers about twice the performance compared to partial.
  - Conversely, if calling partial 100 times only doubles the time, perhaps there's no need to be overly concerned with calling it 5 or 10 times?
  - In this test, the same partial was called 100 times, but the result might differ if different partials are called.
- In both local and production environments, partial_collection performed better than direct coding.
  - With direct coding, the execution is linear without considering the number of items. In contrast, using render collection seems to perform better in terms of string generation cost, as it counts the number of items first and then