LoginSignup
2
1

More than 1 year has passed since last update.

【Rails】stimulus.js × view-component やってみた

Last updated at Posted at 2021-10-04

概要

stimulus.js × view-componentの導入を学んだので、
記録のために残しておきます。

今回のゴールは stimulus.js × view-component
以下の入力欄に文字を入力し、Greetを押すと、横に「Hello, 〇〇!」と表示されたら成功です。
スクリーンショット 2021-10-04 15.54.01.png
      ↓↓↓
スクリーンショット 2021-10-04 15.55.20.png

参考資料

stimulus公式ドキュメント
viewcomponent公式ドキュメント

環境

・Mac M1 バージョン11.4
・Ruby 2.6.8
・Rails 6.1.4.1

手順① アプリを作成

まずは以下のコマンドで新しくファイルを作成します。

% rails new stimulus-view-component

これで必要なファイルがインストールされました。

手順② stimulusをインストール

以下のURLを参考にstimulusのインストール方法を確認します。
https://github.com/hotwired/stimulus-rails

まずはgemfileに以下を記述します。

gemfile
gem 'stimulus-rails'

続いて以下のコマンドを順番に実行します。

% ./bin/bundle install.

% ./bin/rails stimulus:install

スクリーンショット 2021-10-04 12.08.30.png

stimulusはインストールは完了しましたが、

You must import "./controllers" in your JavaScript entrypoint

私の環境では、赤字でこのようなエラーが出ました。

「"./controllers"」の設定をしてあげる必要があるため、
app/javascript/packs/application.js に
「import "controllers"」を追記します。
以下の通りです。

app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()

import "controllers"  // ← これを追記

これでstimulusのインストールが完了しました。

次にview-componentをインストールしていきます。

手順③ view-componentのインストール

view-component の公式ドキュメントを参考にしながらインストールしていきます。
https://viewcomponent.org/guide/getting-started.html

スクリーンショット 2021-10-04 13.39.53.png

最初に、view_componentのgemをgemfileに追記します。

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

gemの記述が完了したら以下のコマンドを実行します。スクリーンショット 2021-10-04 13.47.54.png

% bundle install

これでインストールが完了しました。

現時点でうまく反映できているか確認するため、
サーバーを動かします。

% rails s

http://localhost:3000/で確認します。

以下のようになっていれば成功です。
スクリーンショット 2021-10-04 14.13.20.png

手順④componentファイルの作成

次に以下の画像の通り実行していきます。
スクリーンショット 2021-10-04 13.41.32.png

以下のコマンドでcomponentファイルを作成します。

% bin/rails generate component Example title

ファイルが以下のように作成されればOKです。
スクリーンショット 2021-10-04 13.49.07.png

作成されたファイルの中のapp/components/example_component.rb が
以下の画像と同じになっているか確認して下さい。
スクリーンショット 2021-10-04 13.51.54.png

確認できたら、今度はapp/components/example_component.html.erb
を以下のように変更します。
スクリーンショット 2021-10-04 13.55.12.png

app/components/example_component.html.erb
<span title="<%= @title %>"><%= content %></span>

手順⑤ viewファイルの作成

view配下に
app/views/home/index.html.erb を作成します。
スクリーンショット 2021-10-04 14.02.19.png

これでviewファイルが作成できたので、公式ドキュメント通りに以下の記述を加えていきます。スクリーンショット 2021-10-04 15.17.13.png

app/views/home/index.html.erb
<%= render(ExampleComponent.new(title: "my title")) do %>
  Hello, World!
<% end %>

手順⑥ stimulusファイル作成

手順①で生成されたファイルの中のapp/assets/javascripts/controllers/hello_controller.js
下記のように書き換えます。

app/assets/javascripts/controllers/hello_controller.js
// app/assets/javascripts/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"

// Connects with data-controller="hello"
export default class extends Controller {
  static targets = [ "name", "output" ]

  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
  }
}

さらにapp/views/home/index.html.erb
以下を追加します。

app/views/home/index.html.erb
<%= render(ExampleComponent.new(title: "my title")) do %>
  Hello, World!
<% end %>

↓下記を追記↓
<div data-controller="hello">
  <input data-hello-target="name" type="text">

  <button data-action="click->hello#greet">
    Greet
  </button>

  <span data-hello-target="output">
  </span>
</div>

これで公式ドキュメントを参考にした、セットアップは終了です。

動くか確かめてみましょう。

スクリーンショット 2021-10-04 14.13.20.png

しかし、これではまだ動きません。

ルーティングとコントローラーを設定していませんでした。
それぞれ設定していきます。

confing/routes.rb
Rails.application.routes.draw do
  root 'home#index'  # こちらを追記
end

これでルーティングの設定は完了です。
続いてコントローラーを設定していきます。

% rails g controller home

作成されたコントローラーに以下を記述します。

app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index   # こちらを追記
  end
end

ルーティングとコントローラーを設定が完了したのでサーバーを動かしていきます。

% rails s

http://localhost:3000/で確認します。

スクリーンショット 2021-10-04 15.39.27.png
上手くいきました!!
スクリーンショット 2021-10-04 15.54.01.png
「Qitta」と入力すると
スクリーンショット 2021-10-04 15.55.20.png
「Hello, Qiita!」
stimulus.js × view-componentがうまく反映されてました。

追加実装

①component配下にまとめる

stimulus.js × view-component を動かすことができましたが、
今のままでは、componentに関するファイルがjavascriptやcomponentsファイルにバラバラに入っているので、今後さらに大きな実装をする際にどれがどのファイルか分かりづらくなってしまいます。
そのため、app/components/の次の配下にexampleを作成し、それぞれまとめていきます。

app/components/example/example_component.rb
app/components/example/example_component.html.erb
app/components/example/hello_controller.js

さらにこれらのファイルを分かりやすい名前に変えます。↓↓↓

app/components/example/component.rb
app/components/example/component.html.erb
app/components/example/component_controller.js

ファイル名を変えたので、それぞれのファイル内の記述も変更していきます。

ファイル内の記述の変更

app/components/example/component.rb
# frozen_string_literal: true

class Example::Component < ViewComponent::Base
  def initialize(title:)
    @title = title
  end

end

# ExampleComponentに「::」を追加
app/components/example/component.html.erb

<span title="<%= @title %>"><%= content %></span>

# ↓↓下記を追記

<div data-controller="example--component">
  <input data-example--component-target="name" type="text">

  <button data-action="click->example--component#greet">
    greet
  </button>

  <span data-example--component-target="output">
  </span>
</div>
app/views/home/index.html.erb

<%= render(Example::Component.new(title: "my title")) %>

# ↑↑↑ExampleComponentに「::」を追記↑↑↑

# ↓↓下記を削除↓↓
<div data-controller="hello">
  <input data-hello-target="name" type="text">

  <button data-action="click->hello#greet">
    Greet
  </button>

  <span data-hello-target="output">
  </span>
</div>
app/components/example/component_controller.js

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "name", "output" ]


  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
  }
}

これでそれぞれのファイルの書き換えは完了しました。

Stimulusの書き方変更

続いてstimulusの公式ドキュメントを見ながら、
example階層にした際の書き方に変更していきます。

スクリーンショット 2021-10-06 11.42.26.png

app/javascript/index.js
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"

const application = Application.start()
const context = require.context("controllers", true, /\.js$/)
const contextComponents = require.context("../../components", true, /_controller\.js$/)
application.load(
  definitionsFromContext(context).concat(
    definitionsFromContext(contextComponents)
  )
)

少し記述を変えていきます。

app/javascript/index.js
import { Application } from "@hotwired/stimulus"
import { definitionsFromContext } from "@hotwired/stimulus-webpack-helpers"

const application = Application.start()
const context = require.context("controllers", true, /\.js$/)
const contextComponents = require.context("../../components", true, /_controller\.js$/)
application.load(
  definitionsFromContext(context).concat(
    definitionsFromContext(contextComponents)
  )
)

require.context("../../components", true, /_controller.js$/)
これによってcomponents配下のcontrollerを一斉に動かすことができるようになります。

@hotwiredのエラーができる方は
package.jsonのファイルを書き換えて
yarn installを実行します。

package.json

# 下記を追記↓↓

"@hotwired/stimulus": "^3.0.0",
"@hotwired/stimulus-webpack-helpers": "^1.0.0",
% yarn install

これで@hotwiredに必要なものはインストールできました。

最後に下記を実行していきます。

スクリーンショット 2021-10-06 11.58.42.png

confing/webpacker.yml

# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
additional_paths: ["app/components"]

# []に"app/components"を追記

これでexample階層を新しく作成し、componen配下をまとめることができました。
動くか確認します。

スクリーンショット 2021-10-04 15.55.20.png

無事動きました!!

*動かない場合は、ターミナル上で「command+R」を押すことでスーパーリロードを実行し、
改善されるかもしれません。

②Stimulusのデフォルトメソッド

スクリーンショット 2021-10-07 10.39.17.png

initialize()

一度、コントローラーが最初にインスタンス化されたときに呼び出される

connect()

コントローラがDOMに接続されているときはいつでも呼び出される

[name]TargetConnected(target: Element)

ターゲットがDOMに接続されているときはいつでも呼び出される

disconnect()

コントローラがDOMから切断されたときはいつでも呼び出される

[name]TargetDisconnected(target: Element)

ターゲットがDOMから切断されたときはいつでも呼び出される

最後に

stimulus.js × view-component は以上になります。
〇〇×〇〇やってみたシリーズは今後も学習するので、
都度、新しく投稿していきます。

【Docker】Quickstart : Compose and Rails やってみた

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1