旧ブログ(ISSEN)から移行しました

【Rails7】Stimulus入門! | 概要 ~ 使い方まで詳しく解説

【Rails7】Stimulus入門! | 概要 ~ 使い方まで詳しく解説

西原月熙
西原月熙9分で読めます

はじめに

この記事の概要

こんにちは、株式会社TOKOSのツキヤです!
今回は、RailsでJavaScriptを扱う際にはスタンダードとなりつつあるStimulusについての簡単な説明から、使い方まで解説します!
個人的には、少ないJavaScriptの記述量でアニメーションやDOM操作が可能となるのでかなりオススメの技術です😎
あまり知らなかった人も、この機会にサラッと学んでみましょう✨

対象読者

  • Stimulusが何なのか知りたい人
  • RailsでDOM操作を行いたい人

Stimulusとは?

Hotwireについて

Stimulusについて解説するために、まずはHotwireという技術について説明します!
Hotwireをひとことで説明すると、「JavaScriptをあんまり書かずに今どきのリッチなアプリケーションを作る」技術です!

今どきのアプリケーションは、様々な動作やアニメーションを駆使してユーザーの使いやすさを上げようとしているものばかりですね💪
ユーザーにとってはどんどん便利になって嬉しいかと思いますが、開発者はそれに比例してどんどん仕事の量が増えてしまいます、、😢
更に、そういったフロントエンドの記述は基本的にJavaScriptで書きますが、RailsエンジニアはJavaScriptをそこまで得意としていない人もいます😨

そこで、Railsはより少ない(JavaScriptの)記述で今どきのアプリケーションを作りたいという方向に舵を切り、その結果としてHotwireという技術が出来上がりました🥳

Hotwireは大きくは「Turbo + Stimulus」という要素で構成されています。

ツキヤツキヤ

Turboについては今回は解説は省略します🙏

Stimulusについて

Hotwireの概要を説明したので、いよいよStimulusの解説に移ります!
Stimulusの主な仕事については、いわゆるDOM操作をさせるものとなります!

  • ボタンが押された時に色を変更
  • ハンバーガーメニューの処理
  • モーダル画面の表示

上記のように、URLの変更無しでの動作を簡単に記述できます😎
もちろんこれ以外にもJavaScriptで行いたい動作もできます!

Stimulusの実態としては、JavaScriptのライブラリです。なので、Rails以外でも使うことはもちろん可能です!
ですが、Railsで使う場合はstimulus-railsというgemがあります。これはStimulusを使いやすくするためのgemで、更に実装を助けてくれるので基本はRails上で使うことがオススメです!

他のJSライブラリとの違い

最近はフロントエンドはVue, Reactが使われる場合がほとんどかと思います。
これらのライブラリと比べたときのメリットは「記述が少ない」「環境構築が不要」ということかと思います!

「記述が少ない」ということについては先程からずっと書いていますよね!
こちらについては後ほど体感してもらいますのでお楽しみに😎

「環境構築が不要」ということについてもかなりメリットかと思います!
通常Vue(Nuxt.js)やReact(Next.js)をフロントエンドとして使用する場合はフロントエンドの環境構築やメンテナンスも必要になります。
このコストが結構大きいですが、Stimulusで実装する場合はかなり楽に導入ができます✨
こちらに関しても次の章で具体的に体感してもらいましょう😎

導入方法

導入方法

では早速Stimulusを導入します!

...と言いましたが、Rails7で$ rails newをする際に自動でインストールされているかと思います💪

Gemfile
# ...
gem "stimulus-rails"

初期時点でちゃんとstimulus-railsが入っていました✨

ツキヤツキヤ

JSの管理にWebpackを使っている場合は、package.json@hotwired/stimulusが入っているよ!

後から導入したい場合は、上記のstimulus-rails(+@hotwired/stimulus)をインストールすることで導入可能です!

ファイル構成

次に、Stimulusの記述するファイルの場所等について説明します!

起点となるファイルは、app/javascript/application.jsです!

app/javascript/application.js
// Entry point for the build script in your package.json
import "@hotwired/turbo-rails"
import "./controllers"

簡単に解説すると、必要なライブラリそのものと実際に自分で書くファイル群を集めるapp/javascript/controllersディレクトリ内のindex.jsを読み込んでいます!
このファイルは基本的には自分では触らないかと思います!

続いて、読み込み先のapp/javascript/controllers/index.jsを確認します!

app/javascript/controllers/index.js
// This file is auto-generated by ./bin/rails stimulus:manifest:update
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName
 
import { application } from "./application"
 
import HelloController from "./hello_controller"
application.register("hello", HelloController)

5行目で、更に同じディレクトリ内のapplication.jsを読み込んでいます。細かくは割愛しますが、application.js内の記述によってやっとStimulusを起動することになります✨

7,8行目の記述については、最初のサンプルファイルとなるhello_controller.jsを読み込んでからStimulusの動作として登録しています。
この記述については、rails generate stimulus 〇〇コマンドを打ってファイルを作成する度に自動で追記されます!
なので、こちらのファイルも基本的には自分で追記しません

使い方・記述方法

Stimulusのファイル作成 ~ 実行

それでは、ここから実際にStimulusのファイルを作成して実際にブラウザで動作を確認するところまで行ってみます!
今回実装する機能は、Stimulusの公式サイトと同じ機能にします!
具体的には、inputタグの中に文字を適当に書いてボタンを押したら、Hello 〇〇というテキストをspanタグに生成するものです!
動作を確認したい方は下記リンクで見てみてください。

Stimulus: A modest JavaScript framework for the HTML you already have.

Stimulus is a JavaScript framework with modest ambitions. It doesn’t seek to take over your entire front-end—in fact, it’s not concerned with rendering HTML at all. Instead, it’s designed to augment your HTML with just enough behavior to make it shine.

stimulus.hotwired.dev

それでは、必要なファイルを作成するために、ターミナルに下記コマンドを打ち込んでください!

ターミナル
rails generate stimulus issen

これで、
・「app/javascript/controllers/index.jsへの追記」
・「app/javascript/controllers/issen_controller.jsの作成」
が行われました。順に確認してみます!

ツキヤツキヤ

"issen"という文字はファイル名に使われる自由な文字列だよ! 実際に開発をする時は意味を持たせるような名前が良いね!

app/javascript/controllers/index.js
// This file is auto-generated by ./bin/rails stimulus:manifest:update
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName
 
import { application } from "./application"
 
import HelloController from "./hello_controller"
application.register("hello", HelloController)
 
import IssenController from "./issen_controller"
application.register("issen", IssenController)

index.jsには、issen_controller.jsを読み込む処理が追加されています!

app/javascript/controllers/issen_controller.js
import { Controller } from "@hotwired/stimulus"
 
// Connects to data-controller="issen"
export default class extends Controller {
  connect() {}
}

issen_controller.jsには、Stimulusの雛形となる記述があります!
このファイルを記述していくことで今回の機能を実装します!

JavaScriptの記述

ここからは、issen_controller.jsと適当なindex.html.erbファイルに追記をしていきます!

index.html.erb

Stimulusの公式ページを適当なところにペーストしてみます!
(お好みでCSSをあててください)

index.html.erb
<!--HTML from anywhere-->
<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>

今回は、controllerファイルの名前がissenなので、helloとなっている部分を全てissenにしてみます!

index.html.erb
<!--HTML from anywhere-->
<div data-controller="issen">
  <input data-issen-target="name" type="text" />
 
  <button data-action="click->issen#greet">Greet</button>
 
  <span data-issen-target="output"> </span>
</div>

合計4箇所を変更しました!
2行目のdata-controller="issen"部分で、このファイルのこの<div>タグ内でissen_controller.jsを使いますという意味になります!
その他の部分は追って解説します!

issen_controller.js

まずは、ちゃんとこのissen_controller.jsindex.html.erbに読み込まれているかを確認します!
次のように追記してください

app/javascript/controllers/issen_controller.js
import { Controller } from "@hotwired/stimulus"
 
// Connects to data-controller="issen"
export default class extends Controller {
  connect() {
    console.log("Hello, I'm issen_controller.js!!!")
  }
}

connect()メソッド内の記述は、このcontrollerが読み込まれた際に実行されます!
そこでconsole.logメソッドを仕込んで実際にブラウザのConsoleにHello, I'm issen_controller.js!!!と表示されるか確認します。

index.html.erbのページをリロードしてみると、

ちゃんと表示されました!
これで上手く動いてくれることが確認できました💪

続いて、機能実装のための記述を追加していきます。
この記述についても、Stimulusの公式ページの内容をベースに追記します!

app/javascript/controllers/issen_controller.js
import { Controller } from "@hotwired/stimulus"
 
// Connects to data-controller="issen"
export default class extends Controller {
  static targets = ["name", "output"]
 
  connect() {
    console.log("Hello, I'm issen_controller.js!!!")
  }
 
  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
  }
}

これで準備完了です!
ブラウザで実際に触ってみましょう!

無事同じ動作をしてくれました✨✨

解説

それでは、なぜこのような動作をするのかの解説をします!
大事なのは、「要素の取得」「動作の発火」です!

要素の取得

data属性の記述によって、StimulusはHTMLのinputタグやspanタグを取得しています!
今回の場合、inputタグはdata-issen-target="name"spanタグはdata-issen-target="output"とかかれていますよね。
この記述でissen_controller.jsname,outputという変数に格納されるということです!
issen_controller.js側にstatic targets = ["name", "output"]という記述をする必要もありますので忘れずに書きましょう!

これで要素をJS側でthis.outputTargetthis.nameTargetというような形で使用できます!

ツキヤツキヤ

変数名によって書き換える場所がやや分かりづらいので注意してください!
data-○○-target="××"の時、○○_controller.jsthis.××Targetになります!

動作の発火

spanタグの中身を書き換えるロジックがgreet()メソッドになります!

app/javascript/controllers/issen_controller.js
// 略
  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
  }
}

このメソッドは「spanタグの中身のテキストをHello + inputタグの中身の文字列に変更します」という内容なりますね!

ではボタンを押した時にどうやってこのgreet()メソッドを発火させているかというと、HTML側のbuttonタグ内のdata-action="click->issen#greet"という記述です!
この記述で、「この要素をクリックした時に、issen_controller.jsgreet()メソッドを実行してください」という内容になります!

ツキヤツキヤ

click部分はeventになります!
なのでfocusmouseover等も使えるよ!

終わりに

今回はStimulusの概要の説明から、簡単な使い方まで説明しました!
実際のJavaScriptの記述は数行でしたが、ちゃんとDOM操作ができましたね、すごい✨

現状はまだまだ参考になる記事があまりないかと思いますが、少し勉強するだけでリッチなUIを作ることができるので頑張ってキャッチアップしましょう!
Railsの勉強をしたい方はこの本が参考になるかと思いますので興味がある方はぜひ読んで見てください🙇‍♂️

次回は細かい命名規則等に触れながら解説予定ですのでお楽しみに😎

【Rails7】Stimulusの命名規則について知ろう!

Rails7でJavascriptを扱う際のフレームワークであるStimulusについての命名規則についての解説をしました。パターン別にどのような命名をする必要があるのか説明しています。Stimulusについて勉強中の方は必見です。

この記事を書いた人

西原月熙
西原月熙

TOKOSのテックリード。上流工程からコーディング、インフラ系まで色々やっている器用貧乏です。最近は特にフロントエンドのキャッチアップに力を入れています💪 好きな音楽はボーカロイドです🤖