ViewComponentを使ってRubyでコンポーネント開発

<h1>はじめに</h1>
この記事はCODEBASE OKINAWA Advent Calendar 2022 15日目の記事です。<br>
今回は自分が今プロジェクトで書いている Ruby on Rails のライブラリViewComponent の導入の仕方やメリットについて書いていきます

<h4>ViewComponent とは</h4>
Rails 6.1 からデフォルトでサポートされるようになったgithub製のgem<br>
render partialという部分テンプレートが使用できるライブラリのより便利になったもので
Componentベースで開発するのでコードの再利用が簡単でテストもしやすいです<br>
<a href="https://viewcomponent.org/">公式ドキュメント</a><br>
<a href="https://github.com/github/view_component">https://github.com/github/view_component</a>

<h4>始め方</h4>
まずはgemを追加します。

```
gem "view_component", require: "view_component/engine"
```

componentを生成
今回は下記のようなボタンを試しに作ります。

![スクリーンショット 2022-12-15 11.02.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3070718/2f7af069-aee5-c28a-0e65-4b063b456f44.png)

`rails generate component コンポーネント名 引数`のコマンドを使用すればコンポーネント名とそこに渡す引数を指定して実行します
ボタンを作成するので今回は引数によって色が変わるように`color`を引数に使用します。

```
bin/rails g component Button color
Running via Spring preloader in process 68330
      create  app/components/button_component.rb
      invoke  rspec
      create    spec/components/button_component_spec.rb
      invoke  erb
      create    app/components/button_component.html.erb
```

app/componentsというディレクトリが作成されるのでその下に .rb と html.erb ファイルが生成されます。
```
app/components/
├── button_component.html.erb
└── button_component.rb
```

※ちなみにcomponentはパーツごとに作成すると思うので実際はディレクトリごとに分けて作成していくことが多いです。
```
app/components/
├── button
	  ├── component.html.erb
	  └── component.rb
```

rails generate component で指定したcolor が引数として initializeに渡されます。
```app/components/button_component.rb
# frozen_string_literal: true

class ButtonComponent < ViewComponent::Base
  def initialize(color:)
    @color = color
  end

end
```

<h4>ボタンの部分をコンポーネント化</h4>

app/components/button_component.html.erbにボタン部分の実装を切り出します`color`オブジェクトは `ButtonComponent` の `@color` が利用できます。
(ボタンの色なのでclass属性内で呼び出しています)

```app/components/button_component.html.erb

<a href=“#” class="text-center relative py-4 border border-gray-300 rounded-lg
<%= @color %><%= border_color %><%= background_color %>” >
黒テキスト
</a>
```
コンポーネントの呼び出し側の一覧画面では render メソッドの引数として `ButtonComponent.new(color: color)` を渡す

```app/views/inquiry/index.html.erb
<div class="w-full border-b border-gray-300 pb-8 mb-8">
	<%= render(ButtonComponent.new(color: color)) %>
</div>
```

<h4>部品や関数の実装</h4>

上記のbutton_component.html.erbで記述した`border_color` は 以前Helperなどに書いていたメソッドですが、それらもComponent内に書くことができます。
そこで定義したメソッドはerbでそのまま呼び出せます。

```app/components/button_component.rb
class IdeaComponent < ViewComponent::Base
  ...

+  def border_color
+    @color.border_color ? 'border-yellow-800' : 'border-black'
+
+  end
end
```

<h4>ViewComponent を使うメリット</h4>

一番はテストやデバッグがしやすいことでした。
ViewComponentであればE2Eテストを書く必要はありませんし、コンポーネントごとにテストが可能です
```
require "view_component/test_helpers"
RSpec.configure do |config|
  config.include ViewComponent::TestHelpers, type: :component
end
```

ButtonComponent では下記のように書きます。
```
require "rails_helper"

RSpec.describe ButtonComponent, type: :component do
  let(:color) { Idea.new(background_color: ‘bg-‘white ) }

  subject(:component) { render_inline(described_class.new(color: color)) }

  it “背景色を”設定 do
    expect(component.css("h4").to_html).to include color.background_color
  end
end
```

<h4>まとめ</h4>

ViewComponentを使用するまでRails自体ほとんど書いたことなかったのですが、フロントエンジニアでもRailsでコンポーネントベースで開発ができる学習コストの低さも魅力です。
今回作成したボタンのtext や label をダイナミックに切り替えるのにReactを併用したりもできるので使い方の幅も広そうです。